library(ggplot2)
library(tidyverse)
library(GGally)
library(ggpubr)

#load the dataframes for the figure

remove cells in the edges : pos.x > 45 & < 1150 pos.y > 45 & < 1000 ##add the replicate info


aic.df <- aic.df %>% 
  mutate(exp.field = paste0(str_split(cell.id, "_", simplify = T)[,2],"_",
                            str_split(cell.id, "_", simplify = T)[,3]),
    colony = case_when(exp.field %in% c("20min_s3", "20min_s4") ~ "Replicate 1", 
                            exp.field %in% c("20min_s5", "20min_s6") ~ "Replicate 2",
                            exp.field %in% c("20min_s7", "20min_s8" , "20min_s9") ~ "Replicate 3"))

aic.df <- aic.df %>% 
  mutate(colony = ifelse(degron == "stable" & red == "pup1-rfp", 
                         case_when(exp.field %in% c("20min_s4", "20min_s5") ~ "Replicate 1",
                                   exp.field %in% c("20min_s6", "20min_s7") ~ "Replicate 2",
                                   exp.field %in% c("20min_s8", "20min_s9") ~ "Replicate 3"), colony)) 
  # filter(value < 0.05)
  

##Cellular attributes

pup1.cell.attr <- read_csv("~/plots/all_data/all_pup1_cell_attr.csv")
Rows: 19396 Columns: 29
── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (4): cell.id, degron, red, treatment
dbl (25): gfp.mean.bg.af.sub.new, gfp.sum.bg.af.sub, area, area.puncta, BB_B, BB_C, Elip_B, Elip_C, no.of.voxels, pos.x, pos.y, spheracity, volume, rfp.mean...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

###pup1-RFP background

pup1.cell.attr <- pup1.cell.attr %>% 
  mutate(exp.field = paste0(str_split(cell.id, "_", simplify = T)[,2],"_",
                            str_split(cell.id, "_", simplify = T)[,3]),
    colony = case_when(exp.field %in% c("20min_s3", "20min_s4") ~ "Replicate 1", 
                            exp.field %in% c("20min_s5", "20min_s6") ~ "Replicate 2",
                            exp.field %in% c("20min_s7", "20min_s8" , "20min_s9") ~ "Replicate 3"))

pup1.cell.attr <- pup1.cell.attr %>% 
  mutate(colony = ifelse(degron == "stable" & red == "pup1-rfp", 
                         case_when(exp.field %in% c("20min_s4", "20min_s5") ~ "Replicate 1",
                                   exp.field %in% c("20min_s6", "20min_s7") ~ "Replicate 2",
                                   exp.field %in% c("20min_s8", "20min_s9") ~ "Replicate 3"), colony)) 
  
#removing the 40min and 60min experiments from the stable gfp experiments
pup1.cell.attr <- pup1.cell.attr %>%
  mutate(exp = str_split(exp.field, "_", simplify = T)[,1]) %>% 
  filter(exp == "20min")

Adding the gfp.sum column for the stable GFP experiment

pup1.cell.attr <- read_csv("~/plots/pup1-rfp-gfp-decay/4-28-21-8hrGFP/data/gfp_stable_filtered.csv") %>% 
  filter(image.no == 1) %>% 
  dplyr::select(cell.id, gfpSumBgAFsub) %>% 
  mutate(cell.id = paste0(cell.id,"_","stable_pup1-rfp_none")) %>% 
  dplyr::rename("gfp.sum.bg.af.sub" = "gfpSumBgAFsub") %>% 
  left_join(pup1.cell.attr %>% 
              filter(degron == "stable") %>% 
              dplyr::select(-gfp.sum.bg.af.sub),., by = "cell.id") %>% 
  bind_rows(pup1.cell.attr %>% 
              filter(degron != "stable"),.)

removing multiple entries of the cell because some cell have more than

multiple.pup1 <- pup1.cell.attr %>% 
  mutate(dapi.mean.bg.sub.puncta = ifelse(is.na(dapi.mean.bg.sub.puncta), 0, dapi.mean.bg.sub.puncta) , 
         rfp.mean.bg.sub.puncta = ifelse(is.na(rfp.mean.bg.sub.puncta), 0 , rfp.mean.bg.sub.puncta)) %>% 
  filter(rfp.mean.bg.sub.puncta > 0) %>% 
  group_by(cell.id) %>% 
  tally() %>% 
  filter(n>1)

pup1.cell.attr<- pup1.cell.attr %>% 
  group_by(cell.id) %>% 
  mutate(rfp.mean.bg.sub.puncta = ifelse(cell.id %in% multiple.pup1$cell.id , mean(rfp.mean.bg.sub.puncta), rfp.mean.bg.sub.puncta),
         rfp.sum.bg.sub.puncta = ifelse(cell.id %in% multiple.pup1$cell.id, sum(rfp.mean.bg.sub.puncta), rfp.sum.bg.sub.puncta)) %>% 
    distinct(cell.id, .keep_all = TRUE) 
  

#proteasome inhibition experiments

protInhi.attr <- read_csv("~/plots/all_data/all_mg135_attr.csv") %>% 
  rename("cell.id" = "unique.trackID") %>% 
  filter(timepoint == 1) %>% 
  mutate(cell.id = paste0(cell.id ,"_",degron,"_",red,"_",treatment)) %>% 
  mutate(exp.field = paste0(str_split(cell.id, "_", simplify = T)[,2],"_",
                            str_split(cell.id, "_", simplify = T)[,3]),
    colony = case_when(exp.field %in% c("20min_s3", "20min_s4") ~ "Replicate 1", 
                            exp.field %in% c("20min_s5", "20min_s6") ~ "Replicate 2",
                            exp.field %in% c("20min_s7", "20min_s8" , "20min_s9") ~ "Replicate 3"))

multiple.proInh <- protInhi.attr %>% 
  mutate(dapi.mean.bg.sub.puncta = ifelse(is.na(dapi.mean.bg.sub.puncta), 0, dapi.mean.bg.sub.puncta) , 
         rfp.mean.bg.sub.puncta = ifelse(is.na(rfp.mean.bg.sub.puncta), 0 , rfp.mean.bg.sub.puncta)) %>% 
  filter(rfp.mean.bg.sub.puncta > 0) %>% 
  group_by(cell.id) %>% 
  tally() %>% 
  filter(n>1)

protInhi.attr <- protInhi.attr %>% 
  group_by(cell.id) %>% 
  mutate(rfp.mean.bg.sub.puncta = ifelse(cell.id %in% multiple.proInh$cell.id , mean(rfp.mean.bg.sub.puncta), rfp.mean.bg.sub.puncta),
         rfp.sum.bg.sub.puncta = ifelse(cell.id %in% multiple.proInh$cell.id, sum(rfp.mean.bg.sub.puncta), rfp.sum.bg.sub.puncta)) %>% 
    distinct(cell.id, .keep_all = TRUE)  
  

Adding the protein inhibition experiment data

pup1.proInhi.attr <- pup1.cell.attr %>% 
  bind_rows(.,protInhi.attr %>% 
              dplyr::select(-time, 
                            -timepoint,
                            -image.no, 
                            -ln.gfp, 
                            -ln.gfp.dif,
                            -trackID,
                            -gfp.intensity.center,
                            -gfp.int.mean,
                            -gfp.int.median,
                           -gfp.int.sum,
                           -no.of.triangles,
                           -field,
                           -time.dif.gfp,
                           -real.time.gfp,
                           -sample,
                           -avg.gfp.bg,
                           -Min_gfp,
                           -gfp.mean.bg.sub,
                           -value,
                           -t80,
                           -t95,
                           -threshold,
                           -threshold_95,
                           -gfp.mean.bg.af.sub,
                           -threshold_80,
                           -Mean_gfp,
                           -image,
                           -experiment,
                           -gfp.sum.bg.sub))

#keeping the dy.dm model parameters

#only dy.dm
dy.pup1.rep1.mat <- aic.df %>% 
  filter(red == "pup1-rfp") %>% 
  filter(ifelse(degron %in% c("stable","stable.2","stable.3"), dy < 0.1, dy < 0.5)) %>% 
  group_by(cell.id) %>% 
  filter(model == "dy.dm") %>% 
  mutate(dm = ifelse(is.na(dm), Inf, dm)) %>%
  filter( dm > 0.000015)

#count the number of cells in each experiment

dy.pup1.rep1.mat %>% group_by(degron, treatment) %>% tally()

#creating the df for the MLR

mlr.df <- dy.pup1.rep1.mat %>% 
  #left join with the df with cellular attributes
  left_join(.,pup1.proInhi.attr, by = c("cell.id","red","treatment","degron", "exp.field","colony")) %>% 
  #remove cells with no rfp puncta info 
  mutate(rfp.mean.bg.sub.puncta = ifelse(is.na(rfp.mean.bg.sub.puncta), 0, rfp.mean.bg.sub.puncta)) %>% 
  filter(rfp.mean.bg.sub.puncta > 0)

#checking how many cells there are in each experiment

mlr.df %>% group_by(degron, treatment) %>% tally()

#looking the placement of single cells in images

##Removing the columns that I wont regress upon

mlr.df <- mlr.df %>% 
  filter(pos.x > 45 & pos.x < 1150,
  pos.y > 45 & pos.y < 1000) %>%
  dplyr::select(-f, 
         -rfp.mean.af.sub.puncta,
         -rfp.sum.af.sub.puncta, 
         -dapi.sum.af.sub.puncta,
         -dapi.mean.af.sub.puncta,
         -model, 
         -k,
         -fevals,
         -gevals, 
         -niter, 
         -convcode, 
         -kkt1,
         -kkt2,
         -value,
         -xtime, 
         # -treatment,
         -rfp.mean.bg.sub,
         -rfp.sum.bg.sub,
         -dapi.mean.bg.sub,
         -dapi.sum.bg.sub,
         -dapi.mean.bg.sub.puncta,
         -area.puncta,
         -BB_B,
         -BB_C,
         -pos.x,
         -pos.y,
         -gfp.sum.bg.af.sub,
         -rfp.sum.bg.sub.puncta,
         -no.of.voxels,
         -volume,
         -spheracity) %>% 
  mutate(shape = Elip_B/Elip_C, 
         t.half = log(2)/dy) %>%
  ungroup() %>%
  dplyr::select(-cell.id, 
                -red,
                -exp.field, 
                -aic,
                -Elip_B,
                -Elip_C, 
                -exp) 

#Regressors to use for MLR

regressors <- c("dm",
                "gfp.mean.bg.af.sub.new",
                # "gfp.sum.bg.af.sub",
                "area",
                # "no.of.voxels",
                # "spheracity",
                # "volume",
                "rfp.mean.bg.sub.puncta",
                # "rfp.sum.bg.sub.puncta",
                "dapi.sum.bg.sub.puncta",
                "shape")

Function to evaluate step R

stepR.fn <- function(reg, df, prt.inh.trt, id.var) {
  #get the estimates
  stepR.est <-
    lapply(reg, function(a) {
      #regressors to remove one by one
      temp.df2 <- df %>%
        dplyr::select(all_of(reg), 
                      degron,
                      t.half,
                      # dy, 
                      colony, 
                      treatment) %>% #removed t.half and replaced with dy
        ungroup() %>%
        dplyr::select(-a)
      
      temp.df2 %>%
        filter(treatment %in% prt.inh.trt) %>%
        split(.[id.var]) %>%
        map(., function(b) {
          lm(t.half ~ .,
             data = b %>% dplyr::select(-degron, -colony, -treatment)) %>%
            broom::tidy()
        }) %>%
        bind_rows(.id = id.var) %>%
        mutate(removed.col = a)
      
    }) %>%
    bind_rows()
  
  #get the stats of the model
  stepR.glance <- lapply(reg, function(a) {
    temp.df2 <- df %>%
      dplyr::select(all_of(reg), degron, t.half,
                    # dy, 
                    colony, treatment) %>% #removed t.half and replaced with dy
      dplyr::select(-a)
    
    temp.df2 %>%
      filter(treatment %in% prt.inh.trt) %>%
      split(.[id.var]) %>%
      map(., function(b) {
        lm(t.half ~ .,
           data = b %>% dplyr::select(-degron,-colony,-treatment)) %>%
          broom::glance()
      }) %>%
      bind_rows(.id = id.var) %>%
      mutate(removed.col = a)
    
  }) %>%
    bind_rows()
  
  #get the fits
  stepR.fit <- lapply(reg, function(a) {
    temp.df2 <- df %>%
      dplyr::select(all_of(reg), degron, t.half,
                    # dy, 
                    colony, treatment) %>% #removed t.half and replaced with dy
      dplyr::select(-a)
    
    temp.df2 %>%
      filter(treatment %in% prt.inh.trt) %>%
      split(.[id.var]) %>%
      map(., function(b) {
        lm(t.half ~ .,
           data = b %>% dplyr::select(-degron, -colony,-treatment))
      })
  })
  
  #output
  stepR.list <- list(stepR.est,
                     stepR.glance,
                     stepR.fit)
  
  names(stepR.list) <- c("stepR.est",
                         "stepR.glance",
                         "stepR.fit")
  return(stepR.list)
}

function to evaluate the full model

fullMLR.fn <- function(regressors, df, prt.inh.trt, id.var) {
  #statistics
  fullR.glance <- df %>%
    ungroup() %>%
    filter(treatment %in% prt.inh.trt) %>%
    dplyr::select(all_of(regressors), 
                  degron, 
                  t.half,
                  # dy, 
                  colony, 
                  treatment) %>% #removed t.half and replaced with dy
    split(.[id.var]) %>%
    map(., function(b) {
      lm(t.half ~ .,
         data = b %>% dplyr::select(-degron, -colony, -treatment)) %>%
        broom::glance()
    }) %>%
    bind_rows(.id = id.var) %>%
    mutate(removed.col = "none")
  
  #estimates
  fullR.est <- df %>%
    ungroup() %>%
    filter(treatment %in% prt.inh.trt) %>%
    dplyr::select(all_of(regressors), 
                  degron,
                  t.half,
                  # dy, 
                  colony, 
                  treatment) %>% #removed t.half and replaced with dy
    split(.[id.var]) %>%
    map(., function(b) {
      lm(t.half ~ .,
         data = b %>% dplyr::select(-degron, -colony,-treatment)) %>%
        broom::tidy()
    }) %>%
    bind_rows(.id = id.var) %>%
    mutate(removed.col = "none")
  
  #fits
  fullMLR.fit <- df %>%
    ungroup() %>%
    filter(treatment %in% prt.inh.trt) %>%
    dplyr::select(all_of(regressors), 
                  degron, 
                  t.half,
                  # dy, 
                  colony, 
                  treatment) %>% #removed t.half and replaced with dy
    split(.[id.var]) %>%
    map(., function(b) {
      lm(t.half ~ .,
         data = b %>% dplyr::select(-degron, -colony, -treatment))
    })
  
  #output
  fullMLR.list <- list(fullR.glance,
                       fullR.est,
                       fullMLR.fit)
  
  names(fullMLR.list) <- c("fullR.glance",
                           "fullR.est",
                           "fullMLR.fit")
  return(fullMLR.list)
}

#df where the two experiments of cln2 and stable-GFP are clubbed

mlr.df2 <- mlr.df %>% 
  filter(degron %in% c("cln2.3","mODC.2","stable.3","stable.2","cln2.4")) %>% 
  mutate(degron = case_when(degron %in% c("cln2.3","cln2.2","cln2","cln2.4") ~ "yeGFP-CLN2",
                            degron %in% c("mODC.2", "mODC")  ~ "yeGFP-mODC",
                            degron %in% c("stable","stable.2","stable.3") ~ "yeGFP")) 
  

step MLR estimates #without the protein inhibition

stepR.list <- stepR.fn(reg = regressors, 
         df = mlr.df2,
         prt.inh.trt = "none",
        id.var = "degron")
Note: Using an external vector in selections is ambiguous.
ℹ Use `all_of(a)` instead of `a` to silence this message.
ℹ See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
fullR.list <- fullMLR.fn(reg = regressors,
                         df = mlr.df2,
                         prt.inh.trt = "none",
                         id.var = "degron")

#2D correlation plots

lapply(regressors[1], function(a){
  mlr.df %>% 
    filter(treatment != "none") %>% 
  mutate(t.half = log(2)/dy) %>%
    # filter(degron %in% c("stable.2","stable.3")) %>% 
    # filter(!(degron %in% c("mODC","cln2.2","cln2","stable"))) %>% 
    # filter(treatment %in% c("dmso1","dmso2")) %>%  %>% 
      ggplot(.,aes(y = t.half, x = .[[a]]))+
    geom_point()+
    stat_cor()+
    # stat_regline_equation()+
    facet_wrap(~treatment , scales = "free")+
    labs(title = a)+
    scale_x_log10()
  
})
[[1]]
Warning: Use of `.[[a]]` is discouraged. Use `.data[[a]]` instead.
Warning: Use of `.[[a]]` is discouraged. Use `.data[[a]]` instead.

#y~x + c single variable regression single regressor statistics

stepR.glance <- lapply(regressors, function(a){
  temp.df2 <- mlr.df %>% 
    ungroup() %>% 
    dplyr::select(-a, -dy)
  
  temp.df2 %>% 
    filter(treatment == "none") %>% 
    split(list(.$degron)) %>% 
    map(.,function(b){
      lm(t.half ~ ., data = b %>% dplyr::select(-degron,-colony,-treatment)) %>% 
        broom::glance()
    }) %>% 
    bind_rows(.id = "degron") %>% 
    mutate(removed.col = a)
   
}) %>% 
  bind_rows()


stepR.glance.dmso <- lapply(regressors, function(a){ #regressors to remove one by one 
  temp.df2 <- mlr.df %>% 
    ungroup() %>% 
    dplyr::select(-a, -dy)
  
  temp.df2 %>% 
    filter(treatment %in% c("dmso1","dmso2")) %>% 
    split(list(.$degron, .$treatment)) %>% 
    map(.,function(b){
      lm(t.half ~ ., data = b %>% dplyr::select(-degron, -colony, -treatment)) %>% 
        broom::glance()
    }) %>% 
    bind_rows(.id = "degron") %>% 
    mutate(removed.col = a)
   
}) %>% 
  bind_rows() 

single regressor estimates

stepR.1var.est <- lapply(regressors, function(a){
  temp.df2 <- temp.df %>% 
    ungroup() %>% 
    dplyr::select(a, t.half,degron)
  
  temp.df2 %>% 
    split(.$degron) %>% 
    map(.,function(b){
      lm(t.half ~ ., data = b %>% dplyr::select(-degron)) %>% 
        broom::tidy()
    }) %>% 
    bind_rows(.id = "degron") %>% 
    mutate(single.col = a)
   
}) %>% 
  bind_rows()

#fits
stepR.1var.fit <- lapply(regressors, function(a){
  temp.df2 <- mlr.df %>% 
    ungroup() %>% 
    dplyr::select(a, t.half,degron)
  
  temp.df2 %>% 
    split(.$degron) %>% 
    map(.,function(b){
      lm(t.half ~ ., data = b %>% dplyr::select(-degron)) 
    }) 
}) 

#testing for one degron

fullMLR.fit <- temp.df %>%
    ungroup() %>% 
    dplyr::select(all_of(regressors), degron,t.half,colony) %>% 
    split(list(.$degron)) %>% 
    map(.,function(b){
      lm(t.half ~ ., data = b %>% dplyr::select(-degron,-colony)) 
    })
Error in `dplyr::select()`:
! Can't subset columns that don't exist.
✖ Column `gfp.sum.bg.af.sub` doesn't exist.
Backtrace:
  1. ... %>% ...
  5. dplyr:::select.data.frame(...)
  8. tidyselect::eval_select(expr(c(...)), .data)
  9. tidyselect:::eval_select_impl(...)
 18. tidyselect:::vars_select_eval(...)
     ...
 21. tidyselect:::reduce_sels(node, data_mask, context_mask, init = init)
 22. tidyselect:::walk_data_tree(new, data_mask, context_mask)
 23. tidyselect:::as_indices_sel_impl(...)
 24. tidyselect:::as_indices_impl(x, vars, call = call, strict = strict)
 25. tidyselect:::chr_as_locations(x, vars, call = call)

#plotting the difference in r2 (full model - dropout model)

deltaR2.plt.all <- bind_rows(fullR.list$fullR.glance, stepR.list$stepR.glance) %>%
    mutate(adj.r.squared = round(adj.r.squared , digits = 4)) %>% 
  # separate(.,degron, into = c("degron","colony"), sep = ".Replicate ") %>%  
   # filter(p.value < 0.05) %>% 
  # group_by(degron, removed.col) %>% 
  dplyr::select(degron, r.squared, removed.col) %>% 
  pivot_wider(values_from = r.squared, names_from = removed.col) %>% 
  rename("Rate of Maturation" = "dm", 
         "GFP" = "gfp.mean.bg.af.sub.new",
         "Area" = "area",
         "Pup1-tDimer2" = "rfp.mean.bg.sub.puncta",
         "DAPI" = "dapi.sum.bg.sub.puncta",
         "Shape" = "shape") %>% 
  pivot_longer(cols = 3:8) %>% 
  mutate(value.ratio = value/ none,
         value.sub = none - value) %>% 
  # filter(degron %in% c("cln2.3","mODC.2","stable.3","stable.2","cln2.4")) %>% 
  # mutate(degron = case_when(degron %in% c("cln2.3","cln2.2","cln2","cln2.4") ~ "GFP-CLN2",
  #                           degron %in% c("mODC.2", "mODC")  ~ "GFP-mODC",
  #                           degron %in% c("stable","stable.2","stable.3") ~ "yeGFP"),
  #        degron = factor(degron , levels = c("GFP-mODC","GFP-CLN2","yeGFP"))) %>%
  mutate(degron = factor(degron , levels = c("yeGFP-mODC","yeGFP-CLN2","yeGFP"))) %>% 
  ggplot(.,aes(y = name, x = value.sub))+
  geom_col(width = 0.2)+
  facet_wrap(~degron, scales = "free")+
  scale_y_discrete(labels = function(x) str_wrap(x, width = 10))+
  xlab(TeX("$Delta(r^{2}_{full} - r^{2}_{step})"))+
  ylab("Regressor Dropped")+
  theme_pubr()+
  theme(text = element_text(size = 8), 
        strip.background = element_blank(),
        axis.text.x = element_text(angle = 30))

deltaR2.plt.all

#transform dm and dapi intensity

stepR.list.trans <- stepR.fn(reg = regressors, 
         df = mlr.df2 %>% 
           mutate(dm = log10(dm)),
         prt.inh.trt = "none",
        id.var = "degron")

fullR.list.trans <- fullMLR.fn(reg = regressors,
                         df = mlr.df2 %>% 
           mutate(dm = log10(dm)),
                         prt.inh.trt = "none",
                         id.var = "degron")

#look at the sign of the estimates

lm(t.half ~ rfp.mean.bg.sub.puncta + dm + gfp.mean.bg.af.sub.new + dapi.sum.bg.sub.puncta, data = mlr.df2 %>% filter(degron == "GFP-mODC"))

Call:
lm(formula = t.half ~ rfp.mean.bg.sub.puncta + dm + gfp.mean.bg.af.sub.new + 
    dapi.sum.bg.sub.puncta, data = mlr.df2 %>% filter(degron == 
    "GFP-mODC"))

Coefficients:
           (Intercept)  rfp.mean.bg.sub.puncta                      dm  gfp.mean.bg.af.sub.new  dapi.sum.bg.sub.puncta  
             5.467e+00              -6.682e-03               6.376e-04               4.482e-03               1.647e-05  

#residual analysis of the models

#residual plots against the fitted values
fullMLR.fit %>% 
  map(.,autoplot)
$cln2

$cln2.2

$cln2.3

$cln2.4

$mODC

$mODC.2

$stable

$stable.2

$stable.3

Observations: from the residual vs fitted plots: For the degron GFPs the residual vs the fitted plot lies around the horizonttal band around 0. but for stable GFP, the residual plot is an open funnel shape. According to page 139 in the intro to linear regression: The patterns in panels b and c indicate that the variance of the errors is not constant. The outward-opening funnel pattern in panel b implies that the variance is an increasing function of y. From the residuals vs regressors plots: in yeGFP: there is a strong funnel shape with the GFP intensity: residuals is negatively related to the GFP intensity.

#t.half vs dm

mlr.df %>% 
  ggplot(.,aes(x = dm, y = dy))+
  geom_point()+
  facet_wrap(~degron, scales = "free")+
  scale_x_log10()

testing multiple colinearity using the full model method = variance inflation factors. vif > 5 for a regressor is problematic

library(car)

fullR.list$fullMLR.fit %>% map(.,vif)

#only the gfp, rfp, dapi regrrssors

regressors.fp <- c("gfp.mean.bg.af.sub.new",
                   "rfp.mean.bg.sub.puncta",
                   "dapi.sum.bg.sub.puncta")

stepR.fp.list <- stepR.fn(reg = regressors.fp, 
                          df = mlr.df2,
                          prt.inh.trt = "none",
                          id.var = "degron")

fullR.fp.list <- fullMLR.fn(regressors = regressors.fp, 
                          df = mlr.df2,
                          prt.inh.trt = "none",
                          id.var = "degron")

#variance inflation factor

vif(full.fp.fit$cln2.3) 
gfp.mean.bg.af.sub.new rfp.mean.bg.sub.puncta dapi.sum.bg.sub.puncta 
              1.085858               1.833896               1.928188 
vif(full.fp.fit$cln2.4) 
gfp.mean.bg.af.sub.new rfp.mean.bg.sub.puncta dapi.sum.bg.sub.puncta 
              1.024273               1.505917               1.477058 
vif(full.fp.fit$mODC.2) 
gfp.mean.bg.af.sub.new rfp.mean.bg.sub.puncta dapi.sum.bg.sub.puncta 
              1.001611               1.808745               1.807391 
vif(full.fp.fit$stable.3)
gfp.mean.bg.af.sub.new rfp.mean.bg.sub.puncta dapi.sum.bg.sub.puncta 
              1.008558               1.181293               1.172121 
vif(full.fp.fit$stable.2) 
gfp.mean.bg.af.sub.new rfp.mean.bg.sub.puncta dapi.sum.bg.sub.puncta 
              1.008374               1.427904               1.437518 

#delta r2 for only the fluorescent proteins as the regressors

deltaR2.plt <- bind_rows(fullR.fp.list$fullR.glance, stepR.fp.list$stepR.glance) %>%
    mutate(adj.r.squared = round(adj.r.squared , digits = 4)) %>% 
  # separate(.,degron, into = c("degron","colony"), sep = ".Replicate ") %>%  
   # filter(p.value < 0.05) %>% 
  # group_by(degron, removed.col) %>% 
  dplyr::select(degron, r.squared, removed.col) %>% 
  pivot_wider(values_from = r.squared, names_from = removed.col) %>% 
  rename("GFP intensity" = "gfp.mean.bg.af.sub.new",
         "Pup1-tDimer" = "rfp.mean.bg.sub.puncta",
         "Total DAPI Int." = "dapi.sum.bg.sub.puncta") %>% 
  pivot_longer(cols = 3:5) %>% 
  mutate(value.ratio = value/ none,
         value.sub = none - value) %>% 
  # filter(degron %in% c("cln2.3","mODC.2","stable.3","stable.2","cln2.4")) %>% 
  # mutate(degron = case_when(degron %in% c("cln2.3","cln2.2","cln2","cln2.4") ~ "GFP-CLN2",
  #                           degron %in% c("mODC.2", "mODC")  ~ "GFP-mODC",
  #                           degron %in% c("stable","stable.2","stable.3") ~ "yeGFP"),
  #        degron = factor(degron , levels = c("GFP-mODC","GFP-CLN2","yeGFP"))) %>%
  mutate(degron = factor(degron , levels = c("yeGFP-mODC","yeGFP-CLN2","yeGFP"))) %>% 
  ggplot(.,aes(y = name, x = value.sub))+
  geom_col(width = 0.2)+
  facet_wrap(~degron, scales = "free")+
  theme(text = element_text(size = 8))+
  # scale_x_log10()+
  xlab(TeX("$Delta(r^{2}_{full} - r^{2}_{step})"))+
  ylab("Regressor Dropped")+
  theme_pubr()+
  theme(text = element_text(size = 8))

deltaR2.plt

#response == dy instead of t.half

bind_rows(fullR.fp.list$fullR.glance, stepR.fp.list$stepR.glance) %>%
    mutate(adj.r.squared = round(adj.r.squared , digits = 4)) %>% 
  # separate(.,degron, into = c("degron","colony"), sep = ".Replicate ") %>%  
   filter(p.value < 0.05) %>% 
  # group_by(degron, removed.col) %>% 
  select(degron, r.squared, removed.col) %>% 
  pivot_wider(values_from = r.squared, names_from = removed.col) %>% 
  rename("GFP intensity" = "gfp.mean.bg.af.sub.new",
         "Pup1-tDimer" = "rfp.mean.bg.sub.puncta",
         "Total DAPI Int." = "dapi.sum.bg.sub.puncta") %>% 
  pivot_longer(cols = 3:5) %>% 
  mutate(value.ratio = value/ none,
         value.sub = none - value) %>% 
   filter(degron %in% c("cln2.3","mODC.2","stable.3","stable.2","cln2.4")) %>% 
  # mutate(degron = case_when(degron %in% c("cln2.3","cln2.2","cln2","cln2.4") ~ "GFP-CLN2",
  #                           degron %in% c("mODC.2", "mODC")  ~ "GFP-mODC",
  #                           degron %in% c("stable","stable.2","stable.3") ~ "yeGFP"),
  #        degron = factor(degron , levels = c("GFP-mODC","GFP-CLN2","yeGFP"))) %>%
  # mutate(degron = factor(degron , levels = c("GFP-mODC","GFP-CLN2","yeGFP"))) %>% 
  ggplot(.,aes(y = name, x = value.sub))+
  geom_col(width = 0.2)+
  facet_wrap(~degron, scales = "free")+
  theme(text = element_text(size = 8))+
  # scale_x_log10()+
  xlab(TeX("$Delta(r^{2}_{full} - r^{2}_{step})"))+
  ylab("Regressor Dropped")+
  theme_pubr()+
  theme(text = element_text(size = 8))
Warning: Removed 1 rows containing missing values (position_stack).

#With the protein inhibitors

#with 6 regressors
stepR.prtInh.list <- stepR.fn(reg = regressors, 
                              df = mlr.df, 
                              prt.inh.trt = c("dmso1","dmso2","1uM","2.5uM","5uM","50uM"), 
                              id.var = "treatment")
fullR.prtInh.list <- fullMLR.fn(reg = regressors, 
                              df = mlr.df, 
                              prt.inh.trt = c("dmso1","dmso2","1uM","2.5uM","5uM","50uM"), 
                              id.var = "treatment")

#with just fluorecent proteins
stepR.prtInh.fp.list <- stepR.fn(reg = regressors.fp, 
                              df = mlr.df, 
                              prt.inh.trt = c("dmso1","dmso2","1uM","2.5uM","5uM","50uM"), 
                              id.var = "treatment")
fullR.prtInh.fp.list <- fullMLR.fn(reg = regressors.fp, 
                              df = mlr.df, 
                              prt.inh.trt = c("dmso1","dmso2","1uM","2.5uM","5uM","50uM"), 
                              id.var = "treatment")

plots

#with 6 regressors
bind_rows(fullR.prtInh.list$fullR.glance, stepR.prtInh.list$stepR.glance) %>%
    mutate(adj.r.squared = round(adj.r.squared , digits = 4)) %>% 
  select(treatment, r.squared, removed.col) %>% 
  pivot_wider(values_from = r.squared, names_from = removed.col) %>% 
  pivot_longer(cols = 3:8) %>% 
  mutate(value.ratio = value/ none,
         value.sub = none - value) %>% 
  ggplot(.,aes(y = name, x = value.sub))+
  geom_col()+
  facet_wrap(~factor(treatment, levels = c("dmso1","dmso2","1uM","2.5uM","5uM","50uM")), scales = "free")+
  theme(text = element_text(size = 8))+
  # scale_x_log10()+
  xlab(TeX("$Delta(r^{2}_{full} - r^{2}_{step})"))+
  ylab("regressor dropped")

#with 3 fluorescent proteins
bind_rows(fullR.prtInh.fp.list$fullR.glance, stepR.prtInh.fp.list$stepR.glance) %>%
    mutate(adj.r.squared = round(adj.r.squared , digits = 4)) %>% 
  select(treatment, r.squared, removed.col) %>% 
  pivot_wider(values_from = r.squared, names_from = removed.col) %>% 
  pivot_longer(cols = 3:5) %>% 
  mutate(value.ratio = value/ none,
         value.sub = none - value) %>% 
  ggplot(.,aes(y = name, x = value.sub))+
  geom_col()+
  facet_wrap(~factor(treatment, levels = c("dmso1","dmso2","1uM","2.5uM","5uM","50uM")), scales = "free")+
  theme(text = element_text(size = 8))+
  # scale_x_log10()+
  xlab(TeX("$Delta(r^{2}_{full} - r^{2}_{step})"))+
  ylab("regressor dropped")

#looked at the outliers

lapply(fullMLR.fit, function(a){
  cooks.distance(a) %>% 
    broom::tidy() %>% 
    arrange(desc(x))
}) 
Warning: 'tidy.numeric' is deprecated.
See help("Deprecated")
Warning: 'tidy.numeric' is deprecated.
See help("Deprecated")
Warning: 'tidy.numeric' is deprecated.
See help("Deprecated")
Warning: 'tidy.numeric' is deprecated.
See help("Deprecated")
Warning: 'tidy.numeric' is deprecated.
See help("Deprecated")
Warning: 'tidy.numeric' is deprecated.
See help("Deprecated")
Warning: 'tidy.numeric' is deprecated.
See help("Deprecated")
Warning: 'tidy.numeric' is deprecated.
See help("Deprecated")
Warning: 'tidy.numeric' is deprecated.
See help("Deprecated")
$cln2

$cln2.2

$cln2.3

$cln2.4

$mODC

$mODC.2

$stable

$stable.2

$stable.3
NA
cooks.distance(fullMLR.fit$cln2.3) %>% broom::tidy() %>% arrange(desc(x))
Warning: 'tidy.numeric' is deprecated.
See help("Deprecated")
lapply(fullMLR.fit, summary)

#df to be used with step function

temp.df.list <- mlr.df2 %>% 
    filter(treatment == "none") %>%  
  # mutate( dm = log10(dm)) %>% 
  split(.$degron)

#using stepAIC from MASS

full.stepAIC.mass %>% map(.,broom::tidy)
$`GFP-CLN2`

$`GFP-mODC`

$yeGFP
NA

#step AIC with all the fp markers + cell shape

full.stepAIC <- lapply(temp.df.list, function(a){
  n <- nrow(a)
 step(lm(t.half ~ ., data = a %>% 
     dplyr::select(regressors,
                   t.half,
                   -dy, 
                   -treatment)), 
     direction = "backward", 
     trace = T,
     # k = log(n),
     k =2 ) #k = 2 when small dataset and k = log(n) where n = no. of observations for when the dataset is large
})
Note: Using an external vector in selections is ambiguous.
ℹ Use `all_of(regressors)` instead of `regressors` to silence this message.
ℹ See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
Start:  AIC=5023.53
t.half ~ dm + gfp.mean.bg.af.sub.new + area + rfp.mean.bg.sub.puncta + 
    dapi.sum.bg.sub.puncta + shape

                         Df Sum of Sq   RSS    AIC
- rfp.mean.bg.sub.puncta  1      32.7 36232 5023.0
- shape                   1      38.8 36239 5023.3
- area                    1      39.3 36239 5023.3
<none>                                36200 5023.5
- dm                      1     247.6 36447 5032.5
- dapi.sum.bg.sub.puncta  1     918.2 37118 5061.8
- gfp.mean.bg.af.sub.new  1    7805.7 44006 5335.7

Step:  AIC=5022.98
t.half ~ dm + gfp.mean.bg.af.sub.new + area + dapi.sum.bg.sub.puncta + 
    shape

                         Df Sum of Sq   RSS    AIC
- shape                   1      37.2 36270 5022.6
<none>                                36232 5023.0
- area                    1      89.4 36322 5024.9
- dm                      1     259.8 36492 5032.5
- dapi.sum.bg.sub.puncta  1     970.8 37203 5063.5
- gfp.mean.bg.af.sub.new  1    7803.3 44036 5334.8

Step:  AIC=5022.63
t.half ~ dm + gfp.mean.bg.af.sub.new + area + dapi.sum.bg.sub.puncta

                         Df Sum of Sq   RSS    AIC
<none>                                36270 5022.6
- area                    1      82.2 36352 5024.3
- dm                      1     249.7 36519 5031.7
- dapi.sum.bg.sub.puncta  1    1048.1 37318 5066.5
- gfp.mean.bg.af.sub.new  1    7848.3 44118 5335.8
Start:  AIC=1261.28
t.half ~ dm + gfp.mean.bg.af.sub.new + area + rfp.mean.bg.sub.puncta + 
    dapi.sum.bg.sub.puncta + shape

                         Df Sum of Sq    RSS    AIC
- shape                   1      1.67 3519.1 1260.1
- dm                      1      2.15 3519.6 1260.3
<none>                                3517.5 1261.3
- rfp.mean.bg.sub.puncta  1      5.47 3522.9 1261.8
- area                    1     85.84 3603.3 1299.2
- dapi.sum.bg.sub.puncta  1     89.54 3607.0 1300.9
- gfp.mean.bg.af.sub.new  1    479.97 3997.4 1471.2

Step:  AIC=1260.06
t.half ~ dm + gfp.mean.bg.af.sub.new + area + rfp.mean.bg.sub.puncta + 
    dapi.sum.bg.sub.puncta

                         Df Sum of Sq    RSS    AIC
- dm                      1      2.17 3521.3 1259.1
<none>                                3519.1 1260.1
- rfp.mean.bg.sub.puncta  1      5.05 3524.2 1260.4
- area                    1     84.64 3603.8 1297.4
- dapi.sum.bg.sub.puncta  1     87.90 3607.0 1298.9
- gfp.mean.bg.af.sub.new  1    482.37 4001.5 1470.9

Step:  AIC=1259.08
t.half ~ gfp.mean.bg.af.sub.new + area + rfp.mean.bg.sub.puncta + 
    dapi.sum.bg.sub.puncta

                         Df Sum of Sq    RSS    AIC
<none>                                3521.3 1259.1
- rfp.mean.bg.sub.puncta  1      5.13 3526.4 1259.5
- area                    1     85.97 3607.3 1297.0
- dapi.sum.bg.sub.puncta  1     87.30 3608.6 1297.7
- gfp.mean.bg.af.sub.new  1    493.27 4014.6 1474.3
Start:  AIC=922.36
t.half ~ dm + gfp.mean.bg.af.sub.new + area + rfp.mean.bg.sub.puncta + 
    dapi.sum.bg.sub.puncta + shape

                         Df Sum of Sq    RSS     AIC
<none>                                2628.7  922.36
- shape                   1      7.60 2636.3  924.18
- area                    1     49.53 2678.2  945.06
- rfp.mean.bg.sub.puncta  1     56.77 2685.5  948.63
- dapi.sum.bg.sub.puncta  1     93.01 2721.7  966.37
- dm                      1    105.69 2734.4  972.52
- gfp.mean.bg.af.sub.new  1    561.29 3190.0 1176.40
full.stepAIC %>% 
  map(., broom::glance) %>% 
  bind_rows(.id = "sample") 
  # filter(sample %in% c("mODC.2","cln2.3","cln2.4","stable.2","stable.3"))

full.stepAIC %>% 
  map(., broom::tidy) 
$yeGFP

$`yeGFP-CLN2`

$`yeGFP-mODC`
  # bind_rows(.id = "sample") %>% 
  # filter(sample %in% c("mODC.2","cln2.3","cln2.4","stable.2","stable.3"), 
         # p.value < 0.05) %>% 

full.stepAIC %>% 
  map(.,function(a){
    a$anova 
  }) %>% 
  bind_rows(.,.id = "degron") %>% 
  mutate(Step = as.character(Step), 
         Step = ifelse(Step == "", "Full",Step)) %>% 
  group_by(degron) %>% 
  mutate(del.aic = AIC[1]-AIC) 


full.stepAIC.fp %>% 
  map(.,function(a){
    a$anova 
  }) %>% 
  bind_rows(.,.id = "degron") %>% 
  mutate(Step = as.character(Step), 
         Step = ifelse(Step == "", "Full",Step)) %>% 
  group_by(degron) %>% 
  mutate(del.aic = AIC[1]-AIC) 
NA
NA

#Plot the aic difference at each step

full.stepAIC %>% 
  map(.,function(a){
    a$anova 
  }) %>% 
  bind_rows(.,.id = "degron") %>% 
  mutate(Step = as.character(Step), 
         Step = ifelse(Step == "", "Full",Step)) %>% 
  group_by(degron) %>% 
  mutate(del.aic = AIC[1]-AIC) %>% 
  select(degron, Step, del.aic) %>% 
  split(.$degron) %>% 
  map(.,function(a){
    a[nrow(a),] %>% 
      mutate(model = "reduced")
  }) %>% 
  bind_rows(.id = "degron") %>% 
  mutate(degron = factor(degron, levels = c("GFP-mODC", "GFP-CLN2","yeGFP"))) %>% 
  ggplot(.,aes(x = del.aic, y = degron))+
  geom_col(width = 0.2)+
  theme(text = element_text(size = 8))+
  # scale_x_log10()+
  xlab(TeX("$Delta(AIC_{full} - AIC_{step})"))+
  ylab("Regressor Dropped")+
  theme_pubr()+
  theme(text = element_text(size = 8))

#step AIC with only the fluorescent markers

#looking at which regressor contributes to the overall variability 
full.stepAIC.fp %>% 
  map(., broom::tidy) 
$`GFP-CLN2`

$`GFP-mODC`

$yeGFP
NA

Variance in t-half explained by each regressor using anova

var.explained
$yeGFP

$`yeGFP-CLN2`

$`yeGFP-mODC`
NA

#plotting the variance explained

remain.reg <- data.frame(sample = c("yeGFP-CLN2","yeGFP-CLN2","yeGFP","yeGFP"), 
                         predictor = c("Rate of Maturation", "Shape","Shape","Pup1"), 
                         var.exp = rep(0,4),
                         value.Pr..F. = rep(0,4))
var.exp.plt <- var.explained %>% 
  bind_rows() %>% 
  bind_rows(.,remain.reg) %>% 
  filter(predictor != "Residuals") %>% 
  dplyr::select(sample, predictor, var.exp,value.Pr..F.) %>% 
  mutate(sample = factor(sample , levels = c("yeGFP-mODC","yeGFP-CLN2","yeGFP"))) %>% 
  # mutate(var.pal = ifelse(value.Pr..F. < 0.05, "<0.05",">0.05")) %>% 
  arrange(sample) %>% 
  ggplot(.,aes(x = predictor, y = var.exp ))+
  geom_col(width = 0.5)+
  facet_wrap(~sample, scales = "free")+
  scale_x_discrete(labels = function(x) str_wrap(x, width = 5))+
  theme_pubr()+
  theme(text = element_text(size = 8),
        axis.line = element_line(size = 0.1),
        strip.background = element_blank())+
  ylim(0,20)+
  ylab("Variance explained (%)")+
  xlab("Cellular features")
var.exp.plt

#stepAIC with proteasome inhibition experiments With all fp regressors

temp.df.list.dmso <- mlr.df %>% 
    filter(treatment != "none") %>%  
  split(.$treatment)

full.stepAIC.fp.dmso <- lapply(temp.df.list.dmso, function(a){
 step(lm(t.half ~ ., data = a %>% 
     dplyr::select(regressors.fp,
                   t.half,
                   -dy, 
                   -treatment)), 
     direction = "backward", trace = T)
})

lapply(full.stepAIC.fp.dmso, summary) %>% map(., broom::tidy) %>% 
  bind_rows(.id = "sample") %>% 
  split(.$sample)

lapply(full.stepAIC.fp.dmso, summary) %>% map(., broom::glance) %>% 
  bind_rows(.id = "sample") %>% 
  split(.$sample)

with fp regressors + celluar shape

mlr.df %>% 
    filter(treatment != "none") %>%  
  split(.$treatment)
$`1uM`

$`2.5uM`

$`50uM`

$`5uM`

$dmso1

$dmso2
NA

Variance in t-half explained by each regressor

full.stepAIC.dmso %>% 
  map(., anova %>% as.data.frame) %>% 
  bind_rows(.id = "sample") %>% 
  rownames_to_column(var = "predictor") %>% 
  # filter(sample %in% c("mODC.2","cln2.3","cln2.4","stable.2","stable.3")) %>% 
  group_by(sample) %>% 
  mutate(var.exp = (value.Sum.Sq/sum(value.Sum.Sq))*100) %>% 
  split(.$sample)
$`1uM`

$`2.5uM`

$`50uM`

$`5uM`

$dmso1

$dmso2
NA

#using regsubsets

library(leaps)
full.regSub.fp <- lapply(temp.df.list, function(a){
  n <- nrow(a)
 regsubsets(t.half ~ ., data = a %>% 
     dplyr::select(regressors.fp,
                   t.half,
                   -dy, 
                   -treatment), 
     nvmax = NULL)
})

regSub.summary <- full.regSub.fp %>% map(.,summary)

lapply(regSub.summary, function(a){
  data.frame(model = a$outmat, 
             cp = a$cp,
             bic = a$bic)
}) %>% bind_rows(.id = "degron") %>% 
  group_by(degron) %>% 
  arrange(degron, cp)
full.regSub <- lapply(temp.df.list, function(a){
  n <- nrow(a)
  
  
 regsubsets(t.half ~ ., data = a %>% 
     dplyr::select(regressors,
                   t.half,
                   -dy, 
                   -treatment), 
     nvmax = NULL)
})

regSub.summary2 <- full.regSub %>% map(.,summary)

lapply(regSub.summary2, function(a){
  data.frame(model = a$outmat, 
             cp = a$cp,
             bic = a$bic)
}) %>% bind_rows(.id = "degron") %>% 
  group_by(degron) %>% 
  arrange(degron, bic
          ) %>% split(.$degron)

#plots:

gfp.6.cor.plt <- mlr.df %>%
  mutate(dm = log10(dm)) %>% 
  filter(degron %in% c("mODC.2", "cln2.3", "cln2.4", "stable.2", "stable.3")) %>%
  dplyr::select(t.half,
         regressors,
         degron) %>%
  rename(
    "GFP" = "gfp.mean.bg.af.sub.new",
    "Pup1-tDimer" = "rfp.mean.bg.sub.puncta",
    "DNA" = "dapi.sum.bg.sub.puncta",
    "Area" = "area"
  ) %>%
  pivot_longer(cols = 2:7) %>%
  mutate(degron = case_when(
      degron %in% c("cln2.3", "cln2.2", "cln2", "cln2.4") ~ "yeGFP-CLN2",
      degron %in% c("mODC.2", "mODC")  ~ "yeGFP-mODC",
      degron %in% c("stable", "stable.2", "stable.3") ~ "yeGFP"
    ),
    degron = factor(degron , levels = c("yeGFP-mODC", "yeGFP-CLN2", "yeGFP"))
  ) %>%
  filter(!(name %in% c("shape","dm"))) %>% 
  ggplot(., aes(x = value, y = t.half)) +
      ggpointdensity::geom_pointdensity(size = 0.2, guides = F) +
      stat_cor(size = 2) +
      geom_smooth(method = "lm", se = FALSE, color = "red4", size = 0.5)+
      facet_wrap(degron ~ name, scales = "free", ncol = 4) +
      theme_bw() +
      labs(x = NULL) +
      theme(text = element_text(size = 8),
            axis.text.x = element_text(angle = 30),
            legend.key.size = unit(2,"mm"), 
            legend.position = "none", 
            axis.line = element_line(size = 0.1))+
  ylab("Half-life [min.]")+
  xlab("A.U")
Note: Using an external vector in selections is ambiguous.
ℹ Use `all_of(regressors)` instead of `regressors` to silence this message.
ℹ See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
This message is displayed once per session.
Warning: Ignoring unknown parameters: guides
  
gfp.6.cor.plt
`geom_smooth()` using formula 'y ~ x'

 mlr.df %>%
  filter(degron %in% c("mODC.2", "cln2.3", "cln2.4", "stable.2", "stable.3")) %>%
  dplyr::select(t.half,
         regressors.fp,
         degron) %>%
  mutate(norm.rfp = rfp.mean.bg.sub.puncta/area) 
Error in `mutate()`:
! Problem while computing `norm.rfp = rfp.mean.bg.sub.puncta/area`.
Caused by error in `rfp.mean.bg.sub.puncta / area`:
! non-numeric argument to binary operator
Backtrace:
 1. ... %>% mutate(norm.rfp = rfp.mean.bg.sub.puncta / area)
 3. dplyr:::mutate.data.frame(., norm.rfp = rfp.mean.bg.sub.puncta/area)
 4. dplyr:::mutate_cols(.data, dplyr_quosures(...), caller_env = caller_env())
 6. mask$eval_all_mutate(quo)

GFP intensity vs t-half cor plot

gfp.Int.cor.plt
`geom_smooth()` using formula 'y ~ x'

#patchwork for 3 cellular features and t-half

cellular.halfLife.plt <- (deltaR2.plt.all/gfp.3.cor.plt)+
  plot_layout(guides = "collect", heights = c(0.3,0.7))+
  plot_annotation(tag_levels = "A")

cellular.halfLife.plt
ggsave(plot = cellular.halfLife.plt, filename = "cellular_halfLife_cor.png", path = "~/plots/paper1/figures/fig_2/", width = 6.5, height = 8)
ggsave(plot = cellular.halfLife.plt, filename = "cellular_halfLife_cor.pdf", path = "~/plots/paper1/figures/fig_2/", width = 6.5, height = 8)

#patchwork for GFP intensity and t-half

gfpInt.halfLife.plt <- (deltaR2.plt.all/gfp.Int.cor.plt)+
  plot_layout(guides = "collect")+
  plot_annotation(tag_levels = "A")

gfpInt.halfLife.plt
`geom_smooth()` using formula 'y ~ x'

ggsave(plot = gfpInt.halfLife.plt, filename = "gfpInt_halfLife_cor.pdf", path = "~/plots/paper1/figures/fig_2/", width = 5.5, height = 6)
`geom_smooth()` using formula 'y ~ x'

#for GRC poster

ggsave(plot =gfp.Int.cor.plt , filename = "gfpInt_cor.pdf",path = "~/plots/paper1/figures/fig_2/", width =12, height = 3)
`geom_smooth()` using formula 'y ~ x'

with prottein inhibition

 mlr.df %>%
  mutate(dm = log10(dm)) %>% 
  filter(degron %in% c ("mODC") ) %>%
  # filter(!(treatment %in% c("none", "dmso1","50uM")), 
         # ifelse(treatment == "5uM", t.half < 138.6294, t.half == t.half)) %>%  
  dplyr::select(t.half,
         regressors,
         degron,
         treatment) %>%
  rename(
    "GFP" = "gfp.mean.bg.af.sub.new",
    "Pup1-tDimer" = "rfp.mean.bg.sub.puncta",
    "DAPI" = "dapi.sum.bg.sub.puncta",
    "Area" = "area"
  ) %>%
  pivot_longer(cols = 2:7) %>%
  mutate(degron = case_when(
    degron %in% c("mODC")  ~ "yeGFP-mODC"),
    treatment = factor(treatment, levels = c("none","dmso1","dmso2","1uM","2.5uM","5uM","50uM"))) %>%
  filter(!(name %in% c("shape","dm"))) %>% 
  ggplot(., aes(x = value, y = t.half)) +
      ggpointdensity::geom_pointdensity(size = 0.2, guides = F) +
      stat_cor(size = 2) +
      geom_smooth(method = "lm", se = FALSE, color = "red4", size = 0.5)+
      facet_grid(treatment ~ name, scales = "free") +
      theme_bw() +
      labs(x = NULL) +
      theme(text = element_text(size = 8),
            axis.text.x = element_text(angle = 30),
            legend.key.size = unit(2,"mm"), 
            legend.position = "none")+
  ylab("Half-Life [min.]")+
  xlab("A.U")
Warning: Ignoring unknown parameters: guides
`geom_smooth()` using formula 'y ~ x'

mlr.df %>%
  mutate(dm = log10(dm)) %>% 
  filter(degron %in% c ("mODC") ) %>%
  filter(!(treatment %in% c("none", "dmso1","50uM")), 
         ifelse(treatment == "5uM", t.half < 138.6294, t.half == t.half)) %>% 
  dplyr::select(t.half,
         regressors,
         degron,
         treatment) %>% 
  ggplot(.,aes(x = area, y = rfp.mean.bg.sub.puncta))+
  geom_point()+
  geom_smooth(method = "lm", se = F)+
  facet_wrap(~treatment)+
  stat_cor()
mlr.df %>% 
  filter(treatment == "none") %>% 
  ggplot(.,aes(x = dapi.sum.bg.sub.puncta))+
  geom_histogram()+
  facet_wrap(~degron, scales = "free")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#ggpairs

gfp.area.cor.ggPair
$`yeGFP-mODC`

 plot: [1,1] [====>----------------------------------------------------------------------------------]  6% est: 0s 
 plot: [1,2] [==========>----------------------------------------------------------------------------] 12% est: 1s 
 plot: [1,3] [===============>-----------------------------------------------------------------------] 19% est: 1s 
 plot: [1,4] [=====================>-----------------------------------------------------------------] 25% est: 1s 
 plot: [2,1] [==========================>------------------------------------------------------------] 31% est: 1s `geom_smooth()` using formula 'y ~ x'

 plot: [2,2] [================================>------------------------------------------------------] 38% est: 1s 
 plot: [2,3] [=====================================>-------------------------------------------------] 44% est: 1s 
 plot: [2,4] [===========================================>-------------------------------------------] 50% est: 1s 
 plot: [3,1] [================================================>--------------------------------------] 56% est: 1s `geom_smooth()` using formula 'y ~ x'

 plot: [3,2] [=====================================================>---------------------------------] 62% est: 1s `geom_smooth()` using formula 'y ~ x'

 plot: [3,3] [===========================================================>---------------------------] 69% est: 0s 
 plot: [3,4] [================================================================>----------------------] 75% est: 0s 
 plot: [4,1] [======================================================================>----------------] 81% est: 0s `geom_smooth()` using formula 'y ~ x'

 plot: [4,2] [===========================================================================>-----------] 88% est: 0s `geom_smooth()` using formula 'y ~ x'

 plot: [4,3] [=================================================================================>-----] 94% est: 0s `geom_smooth()` using formula 'y ~ x'

 plot: [4,4] [=======================================================================================]100% est: 0s 
                                                                                                                   

$`yeGFP-CLN2`

 plot: [1,1] [====>----------------------------------------------------------------------------------]  6% est: 0s 
 plot: [1,2] [==========>----------------------------------------------------------------------------] 12% est: 0s 
 plot: [1,3] [===============>-----------------------------------------------------------------------] 19% est: 1s 
 plot: [1,4] [=====================>-----------------------------------------------------------------] 25% est: 1s 
 plot: [2,1] [==========================>------------------------------------------------------------] 31% est: 1s `geom_smooth()` using formula 'y ~ x'

 plot: [2,2] [================================>------------------------------------------------------] 38% est: 1s 
 plot: [2,3] [=====================================>-------------------------------------------------] 44% est: 1s 
 plot: [2,4] [===========================================>-------------------------------------------] 50% est: 1s 
 plot: [3,1] [================================================>--------------------------------------] 56% est: 1s `geom_smooth()` using formula 'y ~ x'

 plot: [3,2] [=====================================================>---------------------------------] 62% est: 1s `geom_smooth()` using formula 'y ~ x'

 plot: [3,3] [===========================================================>---------------------------] 69% est: 0s 
 plot: [3,4] [================================================================>----------------------] 75% est: 0s 
 plot: [4,1] [======================================================================>----------------] 81% est: 0s `geom_smooth()` using formula 'y ~ x'

 plot: [4,2] [===========================================================================>-----------] 88% est: 0s `geom_smooth()` using formula 'y ~ x'

 plot: [4,3] [=================================================================================>-----] 94% est: 0s `geom_smooth()` using formula 'y ~ x'

 plot: [4,4] [=======================================================================================]100% est: 0s 
                                                                                                                   

$yeGFP

 plot: [1,1] [====>----------------------------------------------------------------------------------]  6% est: 0s 
 plot: [1,2] [==========>----------------------------------------------------------------------------] 12% est: 0s 
 plot: [1,3] [===============>-----------------------------------------------------------------------] 19% est: 1s 
 plot: [1,4] [=====================>-----------------------------------------------------------------] 25% est: 1s 
 plot: [2,1] [==========================>------------------------------------------------------------] 31% est: 1s `geom_smooth()` using formula 'y ~ x'

 plot: [2,2] [================================>------------------------------------------------------] 38% est: 1s 
 plot: [2,3] [=====================================>-------------------------------------------------] 44% est: 0s 
 plot: [2,4] [===========================================>-------------------------------------------] 50% est: 0s 
 plot: [3,1] [================================================>--------------------------------------] 56% est: 0s `geom_smooth()` using formula 'y ~ x'

 plot: [3,2] [=====================================================>---------------------------------] 62% est: 0s `geom_smooth()` using formula 'y ~ x'

 plot: [3,3] [===========================================================>---------------------------] 69% est: 0s 
 plot: [3,4] [================================================================>----------------------] 75% est: 0s 
 plot: [4,1] [======================================================================>----------------] 81% est: 0s `geom_smooth()` using formula 'y ~ x'

 plot: [4,2] [===========================================================================>-----------] 88% est: 0s `geom_smooth()` using formula 'y ~ x'

 plot: [4,3] [=================================================================================>-----] 94% est: 0s `geom_smooth()` using formula 'y ~ x'

 plot: [4,4] [=======================================================================================]100% est: 0s 
                                                                                                                   

ggsave(plot = gfp.area.cor.ggPair$`yeGFP-mODC`, filename = "gfp_mODC_4Cor_ggP.png", path = "~/plots/paper1/figures/fig_2/", width = 4, height = 3.5)

ggsave(plot = gfp.area.cor.ggPair$`yeGFP-mODC`, filename = "gfp_mODC_4Cor_ggP.pdf", path = "~/plots/paper1/figures/fig_2/", width = 4, height = 3.5)

ggsave(plot = gfp.area.cor.ggPair$`yeGFP-CLN2`, filename = "gfp_cln2_4Cor_ggP.png", path = "~/plots/paper1/figures/fig_2/", width = 4, height = 3.5)

ggsave(plot = gfp.area.cor.ggPair$`yeGFP-CLN2`, filename = "gfp_cln2_4Cor_ggP.pdf", path = "~/plots/paper1/figures/fig_2/", width = 4, height = 3.5)

ggsave(plot = gfp.area.cor.ggPair$`yeGFP`, filename = "gfp_4Cor_ggP.png", path = "~/plots/paper1/figures/fig_2/", width = 4, height = 3.5)

ggsave(plot = gfp.area.cor.ggPair$`yeGFP`, filename = "gfp_4Cor_ggP.pdf", path = "~/plots/paper1/figures/fig_2/", width = 4, height = 3.5)
test.ggP <- (wrap_elements(ggmatrix_gtable(gfp.area.cor.ggPair$`yeGFP-mODC`))|wrap_elements(ggmatrix_gtable(gfp.area.cor.ggPair$`yeGFP-CLN2`))| wrap_elements(ggmatrix_gtable(gfp.area.cor.ggPair$yeGFP)))+
 plot_annotation(tag_levels = "A")
ggsave(plot = test.ggP, filename = "test_ggP.pdf", path = "~/plots/paper1/figures/fig_2/", width = 6.5, height = 3)

#area vs pup1 vs dna vs gfp

df_corSup_fig <- mlr.df %>%
  filter(degron %in% c("mODC.2", "cln2.3", "cln2.4", "stable.2", "stable.3")) %>%
  dplyr::select(t.half,
         regressors,
         degron) %>%
  rename(
    "GFP" = "gfp.mean.bg.af.sub.new",
    "Pup1-tDimer" = "rfp.mean.bg.sub.puncta",
    "DNA" = "dapi.sum.bg.sub.puncta",
    "Area" = "area"
  ) %>%
  dplyr::select(Area, DNA, `Pup1-tDimer`,GFP,degron ) %>% 
  mutate(
    degron = case_when(
      degron %in% c("cln2.3", "cln2.4") ~ "yeGFP-CLN2",
      degron %in% c("mODC.2")  ~ "yeGFP-mODC",
      degron %in% c("stable.2", "stable.3") ~ "yeGFP"
    ),
    degron = factor(degron , levels = c("yeGFP-mODC", "yeGFP-CLN2", "yeGFP"))
  ) 

area.pup1 <- df_corSup_fig %>% 
  filter(degron == "yeGFP-mODC") %>% 
  ggplot(.,aes(x = Area, y = `Pup1-tDimer`))+
  ggpointdensity::geom_pointdensity(size = 0.2, guides = F) +
      stat_cor(size = 3) +
      geom_smooth(method = "lm", se = FALSE, color = "red4", size = 0.5)+
      theme_bw() +
      labs(x = NULL) +
      theme(text = element_text(size = 8),
            axis.text.x = element_text(angle = 30),
            legend.key.size = unit(2,"mm"), 
            legend.position = "none", 
            axis.line = element_line(size = 0.1))+
  ylab("Pup1-tDimer [A.U]")+
  xlab("Area [A.U]")
Warning: Ignoring unknown parameters: guides
dna.pup1 <- df_corSup_fig %>% 
  filter(degron == "yeGFP-mODC") %>% 
  ggplot(.,aes(x = DNA, y = `Pup1-tDimer`))+
  ggpointdensity::geom_pointdensity(size = 0.2, guides = F) +
      stat_cor(size = 3) +
      geom_smooth(method = "lm", se = FALSE, color = "red4", size = 0.5)+
      theme_bw() +
      labs(x = NULL) +
      theme(text = element_text(size = 8),
            axis.text.x = element_text(angle = 30),
            legend.key.size = unit(2,"mm"), 
            legend.position = "none", 
            axis.line = element_line(size = 0.1))+
  ylab("Pup1-tDimer [A.U]")+
  xlab("DNA [A.U]")
Warning: Ignoring unknown parameters: guides
dna.area <- df_corSup_fig %>%
  filter(degron == "yeGFP-mODC") %>% 
  ggplot(.,aes(x = DNA, y = Area))+
  ggpointdensity::geom_pointdensity(size = 0.2, guides = F) +
      stat_cor(size = 3) +
      geom_smooth(method = "lm", se = FALSE, color = "red4", size = 0.5)+
      theme_bw() +
      labs(x = NULL) +
      theme(text = element_text(size = 8),
            axis.text.x = element_text(angle = 30),
            legend.key.size = unit(2,"mm"), 
            legend.position = "none", 
            axis.line = element_line(size = 0.1))+
  ylab("Area [A.U]")+
  xlab("DNA [A.U]")
Warning: Ignoring unknown parameters: guides
gfpInt.cor.plt <- df_corSup_fig %>% 
  pivot_longer(cols = 1:3) %>% 
  # filter(degron == "yeGFP-mODC") %>% 
  ggplot(.,aes(x = value, y = GFP))+
  ggpointdensity::geom_pointdensity(size = 0.2, guides = F) +
      stat_cor(size = 3) +
      geom_smooth(method = "lm", se = FALSE, color = "red4", size = 0.5)+
  facet_wrap(degron~name, scales = "free")+
      theme_bw() +
      labs(x = NULL) +
      theme(text = element_text(size = 8),
            axis.text.x = element_text(angle = 30),
            legend.key.size = unit(2,"mm"), 
            legend.position = "none", 
            axis.line = element_line(size = 0.1))+
  xlab("A.U")
Warning: Ignoring unknown parameters: guides
ggsave(plot = test_cor, filename = "area.pup1.dna.gfp_cor.pdf", path = "~/plots/paper1/figures/fig_2/", width = 6.5, height = 7)
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'

#Partial correlations ppcor

#partial correlations
ppCor.list <- mlr.df2 %>% 
  filter(treatment == "none") %>% split(.$degron) %>% 
  map(.,function(a){
    a <- a %>% 
      dplyr::select(t.half, area,  dapi.sum.bg.sub.puncta, rfp.mean.bg.sub.puncta, gfp.mean.bg.af.sub.new) %>% 
      na.omit()
    ppcor::pcor(a)
  })

#correlations
cor.all <- mlr.df2 %>% 
  filter(treatment == "none") %>%  
  split(.$degron) %>% 
  map(.,function(a){
     a <- a %>% 
      dplyr::select(t.half, area, dapi.sum.bg.sub.puncta,rfp.mean.bg.sub.puncta, gfp.mean.bg.af.sub.new) %>% 
      na.omit()
     cor(a)
  })
ppCor.df <- ppCor.list %>% 
  map(.,function(a){
    a$estimate %>% 
      as.data.frame() %>% 
      rownames_to_column(var = "regressor") %>% 
      dplyr::select(t.half, regressor) %>% 
      left_join(.,a$p.value%>% 
                  as.data.frame() %>% 
                  rownames_to_column(var = "regressor") %>% 
                  rename("p.value" = "t.half") %>% 
      dplyr::select(p.value, regressor), by = "regressor")
  }) %>% 
  bind_rows(.id = "degron")

single.core.df <- cor.all %>% 
  map(.,function(a){
    a%>% 
      as.data.frame() %>% 
      rownames_to_column(var = "regressor") %>% 
      dplyr::select(t.half, regressor)
  }) %>% 
  bind_rows(.id = "degron") %>% 
  rename("single.core"="t.half")
library(gtools)
ppCoor.fig <- ppCor.df %>% 
  left_join(.,single.core.df, by = c("degron","regressor")) %>% 
  rename("Partial-Pariwise"="t.half",
         "Standard-Pariwise" = "single.core") %>% 
  pivot_longer(cols = c("Partial-Pariwise","Standard-Pariwise")) %>% 
   mutate(regressor = case_when(regressor == "gfp.mean.bg.af.sub.new" ~ "GFP" ,
                               regressor == "area" ~ "Area",
                               regressor == "rfp.mean.bg.sub.puncta" ~ "Pup1",
                               regressor == "dapi.sum.bg.sub.puncta" ~ "DNA" ,
                               regressor == "t.half" ~ "half-life"), 
          degron = factor(degron, levels = c("yeGFP-mODC","yeGFP-CLN2","yeGFP")), 
          name = factor(name , levels = c("Standard-Pariwise", "Partial-Pariwise")), 
          sig = stars.pval(p.value), 
          sig = ifelse(sig == " ", "NS", sig)) %>% 
  # filter(p.value < 0.05) %>% 
  filter(regressor != "half-life") %>% 
  ggplot(.,aes(x = regressor , y = value, fill = name))+
  geom_col(width = 0.5, position = "dodge")+
  facet_wrap(~degron)+
  geom_hline(yintercept = 0, size = 0.1)+
  scale_y_continuous(breaks = seq(-0.5,0.5, by = 0.1))+
  theme_pubr()+
  theme(text = element_text(size = 8),
            legend.key.size = unit(4,"mm"),
        legend.position = "top", 
        axis.line = element_line(size = 0.1),
        strip.background = element_blank())+
  scale_fill_manual(values = c("lightsteelblue4" ," steelblue4"), name = NULL)+
  ylab("Correlation with Half-life ")+
  xlab("Cellular features")

ppCoor.fig

#patchwork for 4 cellular features (area, gfp, dapi, pup1) and t-half

(gfp.6.cor.plt/var.exp.plt/ppCoor.fig)
`geom_smooth()` using formula 'y ~ x'

ggsave(plot = gfp.4cor.hf.ppCor.plt, filename = "gfp_4cor_halfLife_ppcor.png", path = "~/plots/paper1/figures/fig_2/", width = 7, height = 9)
`geom_smooth()` using formula 'y ~ x'
ggsave(plot = gfp.4cor.hf.ppCor.plt, filename = "gfp_4cor_halfLife_ppcor.pdf", path = "~/plots/paper1/figures/fig_2/", width = 7, height = 9)
`geom_smooth()` using formula 'y ~ x'

#with protein inhibion

ppCor.PrtIn.list <- mlr.df %>% 
    filter(treatment != "none") %>%  
  filter(ifelse(treatment == "5uM", t.half < 138.6294, t.half == t.half)) %>% 
  split(.$treatment) %>% 
  map(.,function(a){
    a <- a %>% 
      dplyr::select(t.half, area, dapi.sum.bg.sub.puncta, rfp.mean.bg.sub.puncta, gfp.mean.bg.af.sub.new) %>%
      na.omit()
    ppcor::pcor(a)
  })

cor.PrtIn.all <- mlr.df %>% 
    filter(treatment != "none") %>%  
  filter(ifelse(treatment == "5uM", t.half < 138.6294, t.half == t.half)) %>% 
  split(.$treatment) %>% 
  map(.,function(a){
    a <- a %>% 
      dplyr::select(t.half, area, dapi.sum.bg.sub.puncta, rfp.mean.bg.sub.puncta, gfp.mean.bg.af.sub.new) %>% 
      na.omit()
    cor(a)
  })
ppCor.PrtIn.df <- ppCor.PrtIn.list %>% 
  map(.,function(a){
    a$estimate %>% 
      as.data.frame() %>% 
      rownames_to_column(var = "regressor") %>% 
      dplyr::select(t.half, regressor) %>% 
      left_join(.,a$p.value%>% 
                  as.data.frame() %>% 
                  rownames_to_column(var = "regressor") %>% 
                  rename("p.value" = "t.half") %>% 
      dplyr::select(p.value, regressor), by = "regressor")
  }) %>% 
  bind_rows(.id = "treatment")

single.core.Prtn.df <- cor.PrtIn.all %>% 
  map(.,function(a){
    a%>% 
      as.data.frame() %>% 
      rownames_to_column(var = "regressor") %>% 
      dplyr::select(t.half, regressor)
  }) %>% 
  bind_rows(.id = "treatment") %>% 
  rename("single.core"="t.half")

correlation of pup1 with mODC with treated with proteasome inhibitors

#when you normalize pup1 with the area

mlr.df %>%
  mutate(dm = log10(dm)) %>% 
  filter(degron %in% c("mODC.2", "cln2.3", "cln2.4", "stable.2", "stable.3")) %>%
  dplyr::select(t.half,
         regressors,
         degron) %>%
  rename(
    "GFP" = "gfp.mean.bg.af.sub.new",
    "Pup1-tDimer" = "rfp.mean.bg.sub.puncta",
    "DNA" = "dapi.sum.bg.sub.puncta",
    "Area" = "area"
  ) %>%
  mutate(norm.pup1 = `Pup1-tDimer`/Area) %>% 
  pivot_longer(cols = c(2:7,9)) %>%
  mutate(degron = case_when(
      degron %in% c("cln2.3", "cln2.2", "cln2", "cln2.4") ~ "yeGFP-CLN2",
      degron %in% c("mODC.2", "mODC")  ~ "yeGFP-mODC",
      degron %in% c("stable", "stable.2", "stable.3") ~ "yeGFP"
    ),
    degron = factor(degron , levels = c("yeGFP-mODC", "yeGFP-CLN2", "yeGFP"))
  ) %>%
  filter(!(name %in% c("shape","dm"))) %>% 
  ggplot(., aes(x = value, y = t.half)) +
      ggpointdensity::geom_pointdensity(size = 0.2, guides = F) +
      stat_cor(size = 2) +
      geom_smooth(method = "lm", se = FALSE, color = "red4", size = 0.5)+
      facet_wrap(degron ~ name, scales = "free", ncol = 4) +
      theme_bw() +
      labs(x = NULL) +
      theme(text = element_text(size = 8),
            axis.text.x = element_text(angle = 30),
            legend.key.size = unit(2,"mm"), 
            legend.position = "none")+
  ylab("Half-Life [min.]")+
  xlab("A.U")
LS0tCnRpdGxlOiAiQ29ycmVsYXRpb25zIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KEdHYWxseSkKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkobGF0ZXgyZXhwKQpsaWJyYXJ5KHBhdGNod29yaykKCmBgYAoKI2xvYWQgdGhlIGRhdGFmcmFtZXMgZm9yIHRoZSBmaWd1cmUKYGBge3J9CmFpYy5kZiA8LSByZWFkX2Nzdigifi9wbG90cy9hbGxfZGF0YS9haWMuY3N2IikKCmFpYy5kZiAlPiUgZmlsdGVyKHRyZWF0bWVudCA9PSAiNXVNIiwgbW9kZWwgPT0gImR5LmRtIikgJT4lIG11dGF0ZSh0LmhhbGYgPSBsb2coMikvZHkpICU+JSBmaWx0ZXIodC5oYWxmID4gMTMwKQoKYGBgCgoKcmVtb3ZlIGNlbGxzIGluIHRoZSBlZGdlcyA6CnBvcy54ID4gNDUgJiA8IDExNTAKcG9zLnkgPiA0NSAmIDwgMTAwMAojI2FkZCB0aGUgcmVwbGljYXRlIGluZm8gCmBgYHtyfQphaWMuZGYgPC0gYWljLmRmICU+JSAKICBtdXRhdGUoZXhwLmZpZWxkID0gcGFzdGUwKHN0cl9zcGxpdChjZWxsLmlkLCAiXyIsIHNpbXBsaWZ5ID0gVClbLDJdLCJfIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9zcGxpdChjZWxsLmlkLCAiXyIsIHNpbXBsaWZ5ID0gVClbLDNdKSwKICAgIGNvbG9ueSA9IGNhc2Vfd2hlbihleHAuZmllbGQgJWluJSBjKCIyMG1pbl9zMyIsICIyMG1pbl9zNCIpIH4gIlJlcGxpY2F0ZSAxIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHAuZmllbGQgJWluJSBjKCIyMG1pbl9zNSIsICIyMG1pbl9zNiIpIH4gIlJlcGxpY2F0ZSAyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cC5maWVsZCAlaW4lIGMoIjIwbWluX3M3IiwgIjIwbWluX3M4IiAsICIyMG1pbl9zOSIpIH4gIlJlcGxpY2F0ZSAzIikpCgphaWMuZGYgPC0gYWljLmRmICU+JSAKICBtdXRhdGUoY29sb255ID0gaWZlbHNlKGRlZ3JvbiA9PSAic3RhYmxlIiAmIHJlZCA9PSAicHVwMS1yZnAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2Vfd2hlbihleHAuZmllbGQgJWluJSBjKCIyMG1pbl9zNCIsICIyMG1pbl9zNSIpIH4gIlJlcGxpY2F0ZSAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHAuZmllbGQgJWluJSBjKCIyMG1pbl9zNiIsICIyMG1pbl9zNyIpIH4gIlJlcGxpY2F0ZSAyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHAuZmllbGQgJWluJSBjKCIyMG1pbl9zOCIsICIyMG1pbl9zOSIpIH4gIlJlcGxpY2F0ZSAzIiksIGNvbG9ueSkpIAogIApgYGAKCiMjQ2VsbHVsYXIgYXR0cmlidXRlcwpgYGB7cn0KcHVwMS5jZWxsLmF0dHIgPC0gcmVhZF9jc3YoIn4vcGxvdHMvYWxsX2RhdGEvYWxsX3B1cDFfY2VsbF9hdHRyLmNzdiIpCmBgYAoKIyMjcHVwMS1SRlAgYmFja2dyb3VuZApgYGB7cn0KcHVwMS5jZWxsLmF0dHIgPC0gcHVwMS5jZWxsLmF0dHIgJT4lIAogIG11dGF0ZShleHAuZmllbGQgPSBwYXN0ZTAoc3RyX3NwbGl0KGNlbGwuaWQsICJfIiwgc2ltcGxpZnkgPSBUKVssMl0sIl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX3NwbGl0KGNlbGwuaWQsICJfIiwgc2ltcGxpZnkgPSBUKVssM10pLAogICAgY29sb255ID0gY2FzZV93aGVuKGV4cC5maWVsZCAlaW4lIGMoIjIwbWluX3MzIiwgIjIwbWluX3M0IikgfiAiUmVwbGljYXRlIDEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cC5maWVsZCAlaW4lIGMoIjIwbWluX3M1IiwgIjIwbWluX3M2IikgfiAiUmVwbGljYXRlIDIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwLmZpZWxkICVpbiUgYygiMjBtaW5fczciLCAiMjBtaW5fczgiICwgIjIwbWluX3M5IikgfiAiUmVwbGljYXRlIDMiKSkKCnB1cDEuY2VsbC5hdHRyIDwtIHB1cDEuY2VsbC5hdHRyICU+JSAKICBtdXRhdGUoY29sb255ID0gaWZlbHNlKGRlZ3JvbiA9PSAic3RhYmxlIiAmIHJlZCA9PSAicHVwMS1yZnAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2Vfd2hlbihleHAuZmllbGQgJWluJSBjKCIyMG1pbl9zNCIsICIyMG1pbl9zNSIpIH4gIlJlcGxpY2F0ZSAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHAuZmllbGQgJWluJSBjKCIyMG1pbl9zNiIsICIyMG1pbl9zNyIpIH4gIlJlcGxpY2F0ZSAyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHAuZmllbGQgJWluJSBjKCIyMG1pbl9zOCIsICIyMG1pbl9zOSIpIH4gIlJlcGxpY2F0ZSAzIiksIGNvbG9ueSkpIAogIApgYGAKCmBgYHtyfQojcmVtb3ZpbmcgdGhlIDQwbWluIGFuZCA2MG1pbiBleHBlcmltZW50cyBmcm9tIHRoZSBzdGFibGUgZ2ZwIGV4cGVyaW1lbnRzCnB1cDEuY2VsbC5hdHRyIDwtIHB1cDEuY2VsbC5hdHRyICU+JQogIG11dGF0ZShleHAgPSBzdHJfc3BsaXQoZXhwLmZpZWxkLCAiXyIsIHNpbXBsaWZ5ID0gVClbLDFdKSAlPiUgCiAgZmlsdGVyKGV4cCA9PSAiMjBtaW4iKQpgYGAKCkFkZGluZyB0aGUgZ2ZwLnN1bSBjb2x1bW4gZm9yIHRoZSBzdGFibGUgR0ZQIGV4cGVyaW1lbnQKYGBge3J9CnB1cDEuY2VsbC5hdHRyIDwtIHJlYWRfY3N2KCJ+L3Bsb3RzL3B1cDEtcmZwLWdmcC1kZWNheS80LTI4LTIxLThockdGUC9kYXRhL2dmcF9zdGFibGVfZmlsdGVyZWQuY3N2IikgJT4lIAogIGZpbHRlcihpbWFnZS5ubyA9PSAxKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjZWxsLmlkLCBnZnBTdW1CZ0FGc3ViKSAlPiUgCiAgbXV0YXRlKGNlbGwuaWQgPSBwYXN0ZTAoY2VsbC5pZCwiXyIsInN0YWJsZV9wdXAxLXJmcF9ub25lIikpICU+JSAKICBkcGx5cjo6cmVuYW1lKCJnZnAuc3VtLmJnLmFmLnN1YiIgPSAiZ2ZwU3VtQmdBRnN1YiIpICU+JSAKICBsZWZ0X2pvaW4ocHVwMS5jZWxsLmF0dHIgJT4lIAogICAgICAgICAgICAgIGZpbHRlcihkZWdyb24gPT0gInN0YWJsZSIpICU+JSAKICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KC1nZnAuc3VtLmJnLmFmLnN1YiksLiwgYnkgPSAiY2VsbC5pZCIpICU+JSAKICBiaW5kX3Jvd3MocHVwMS5jZWxsLmF0dHIgJT4lIAogICAgICAgICAgICAgIGZpbHRlcihkZWdyb24gIT0gInN0YWJsZSIpLC4pCmBgYAoKcmVtb3ZpbmcgbXVsdGlwbGUgZW50cmllcyBvZiB0aGUgY2VsbCBiZWNhdXNlIHNvbWUgY2VsbCBoYXZlIG1vcmUgdGhhbiAKYGBge3J9Cm11bHRpcGxlLnB1cDEgPC0gcHVwMS5jZWxsLmF0dHIgJT4lIAogIG11dGF0ZShkYXBpLm1lYW4uYmcuc3ViLnB1bmN0YSA9IGlmZWxzZShpcy5uYShkYXBpLm1lYW4uYmcuc3ViLnB1bmN0YSksIDAsIGRhcGkubWVhbi5iZy5zdWIucHVuY3RhKSAsIAogICAgICAgICByZnAubWVhbi5iZy5zdWIucHVuY3RhID0gaWZlbHNlKGlzLm5hKHJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEpLCAwICwgcmZwLm1lYW4uYmcuc3ViLnB1bmN0YSkpICU+JSAKICBmaWx0ZXIocmZwLm1lYW4uYmcuc3ViLnB1bmN0YSA+IDApICU+JSAKICBncm91cF9ieShjZWxsLmlkKSAlPiUgCiAgdGFsbHkoKSAlPiUgCiAgZmlsdGVyKG4+MSkKCnB1cDEuY2VsbC5hdHRyPC0gcHVwMS5jZWxsLmF0dHIgJT4lIAogIGdyb3VwX2J5KGNlbGwuaWQpICU+JSAKICBtdXRhdGUocmZwLm1lYW4uYmcuc3ViLnB1bmN0YSA9IGlmZWxzZShjZWxsLmlkICVpbiUgbXVsdGlwbGUucHVwMSRjZWxsLmlkICwgbWVhbihyZnAubWVhbi5iZy5zdWIucHVuY3RhKSwgcmZwLm1lYW4uYmcuc3ViLnB1bmN0YSksCiAgICAgICAgIHJmcC5zdW0uYmcuc3ViLnB1bmN0YSA9IGlmZWxzZShjZWxsLmlkICVpbiUgbXVsdGlwbGUucHVwMSRjZWxsLmlkLCBzdW0ocmZwLm1lYW4uYmcuc3ViLnB1bmN0YSksIHJmcC5zdW0uYmcuc3ViLnB1bmN0YSkpICU+JSAKICAgIGRpc3RpbmN0KGNlbGwuaWQsIC5rZWVwX2FsbCA9IFRSVUUpIAogIApgYGAKCgojcHJvdGVhc29tZSBpbmhpYml0aW9uIGV4cGVyaW1lbnRzCmBgYHtyfQpwcm90SW5oaS5hdHRyIDwtIHJlYWRfY3N2KCJ+L3Bsb3RzL2FsbF9kYXRhL2FsbF9tZzEzNV9hdHRyLmNzdiIpICU+JSAKICByZW5hbWUoImNlbGwuaWQiID0gInVuaXF1ZS50cmFja0lEIikgJT4lIAogIGZpbHRlcih0aW1lcG9pbnQgPT0gMSkgJT4lIAogIG11dGF0ZShjZWxsLmlkID0gcGFzdGUwKGNlbGwuaWQgLCJfIixkZWdyb24sIl8iLHJlZCwiXyIsdHJlYXRtZW50KSkgJT4lIAogIG11dGF0ZShleHAuZmllbGQgPSBwYXN0ZTAoc3RyX3NwbGl0KGNlbGwuaWQsICJfIiwgc2ltcGxpZnkgPSBUKVssMl0sIl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX3NwbGl0KGNlbGwuaWQsICJfIiwgc2ltcGxpZnkgPSBUKVssM10pLAogICAgY29sb255ID0gY2FzZV93aGVuKGV4cC5maWVsZCAlaW4lIGMoIjIwbWluX3MzIiwgIjIwbWluX3M0IikgfiAiUmVwbGljYXRlIDEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cC5maWVsZCAlaW4lIGMoIjIwbWluX3M1IiwgIjIwbWluX3M2IikgfiAiUmVwbGljYXRlIDIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwLmZpZWxkICVpbiUgYygiMjBtaW5fczciLCAiMjBtaW5fczgiICwgIjIwbWluX3M5IikgfiAiUmVwbGljYXRlIDMiKSkKCm11bHRpcGxlLnByb0luaCA8LSBwcm90SW5oaS5hdHRyICU+JSAKICBtdXRhdGUoZGFwaS5tZWFuLmJnLnN1Yi5wdW5jdGEgPSBpZmVsc2UoaXMubmEoZGFwaS5tZWFuLmJnLnN1Yi5wdW5jdGEpLCAwLCBkYXBpLm1lYW4uYmcuc3ViLnB1bmN0YSkgLCAKICAgICAgICAgcmZwLm1lYW4uYmcuc3ViLnB1bmN0YSA9IGlmZWxzZShpcy5uYShyZnAubWVhbi5iZy5zdWIucHVuY3RhKSwgMCAsIHJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEpKSAlPiUgCiAgZmlsdGVyKHJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEgPiAwKSAlPiUgCiAgZ3JvdXBfYnkoY2VsbC5pZCkgJT4lIAogIHRhbGx5KCkgJT4lIAogIGZpbHRlcihuPjEpCgpwcm90SW5oaS5hdHRyIDwtIHByb3RJbmhpLmF0dHIgJT4lIAogIGdyb3VwX2J5KGNlbGwuaWQpICU+JSAKICBtdXRhdGUocmZwLm1lYW4uYmcuc3ViLnB1bmN0YSA9IGlmZWxzZShjZWxsLmlkICVpbiUgbXVsdGlwbGUucHJvSW5oJGNlbGwuaWQgLCBtZWFuKHJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEpLCByZnAubWVhbi5iZy5zdWIucHVuY3RhKSwKICAgICAgICAgcmZwLnN1bS5iZy5zdWIucHVuY3RhID0gaWZlbHNlKGNlbGwuaWQgJWluJSBtdWx0aXBsZS5wcm9JbmgkY2VsbC5pZCwgc3VtKHJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEpLCByZnAuc3VtLmJnLnN1Yi5wdW5jdGEpKSAlPiUgCiAgICBkaXN0aW5jdChjZWxsLmlkLCAua2VlcF9hbGwgPSBUUlVFKSAgCiAgCgpgYGAKQWRkaW5nIHRoZSBwcm90ZWluIGluaGliaXRpb24gZXhwZXJpbWVudCBkYXRhCmBgYHtyfQpwdXAxLnByb0luaGkuYXR0ciA8LSBwdXAxLmNlbGwuYXR0ciAlPiUgCiAgYmluZF9yb3dzKC4scHJvdEluaGkuYXR0ciAlPiUgCiAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdCgtdGltZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAtdGltZXBvaW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLWltYWdlLm5vLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1sbi5nZnAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgLWxuLmdmcC5kaWYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAtdHJhY2tJRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1nZnAuaW50ZW5zaXR5LmNlbnRlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1nZnAuaW50Lm1lYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAtZ2ZwLmludC5tZWRpYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC1nZnAuaW50LnN1bSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgLW5vLm9mLnRyaWFuZ2xlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgLWZpZWxkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAtdGltZS5kaWYuZ2ZwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAtcmVhbC50aW1lLmdmcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgLXNhbXBsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgLWF2Zy5nZnAuYmcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC1NaW5fZ2ZwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAtZ2ZwLm1lYW4uYmcuc3ViLAogICAgICAgICAgICAgICAgICAgICAgICAgICAtdmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC10ODAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC10OTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC10aHJlc2hvbGQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC10aHJlc2hvbGRfOTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC1nZnAubWVhbi5iZy5hZi5zdWIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC10aHJlc2hvbGRfODAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIC1NZWFuX2dmcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgLWltYWdlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAtZXhwZXJpbWVudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgLWdmcC5zdW0uYmcuc3ViKSkKYGBgCgoKI2tlZXBpbmcgdGhlIGR5LmRtIG1vZGVsIHBhcmFtZXRlcnMgCmBgYHtyfQojb25seSBkeS5kbQpkeS5wdXAxLnJlcDEubWF0IDwtIGFpYy5kZiAlPiUgCiAgZmlsdGVyKHJlZCA9PSAicHVwMS1yZnAiKSAlPiUgCiAgZmlsdGVyKGlmZWxzZShkZWdyb24gJWluJSBjKCJzdGFibGUiLCJzdGFibGUuMiIsInN0YWJsZS4zIiksIGR5IDwgMC4xLCBkeSA8IDAuNSkpICU+JSAKICBncm91cF9ieShjZWxsLmlkKSAlPiUgCiAgZmlsdGVyKG1vZGVsID09ICJkeS5kbSIpICU+JSAKICBtdXRhdGUoZG0gPSBpZmVsc2UoaXMubmEoZG0pLCBJbmYsIGRtKSkgJT4lCiAgZmlsdGVyKCBkbSA+IDAuMDAwMDE1KQpgYGAKCiNjb3VudCB0aGUgbnVtYmVyIG9mIGNlbGxzIGluIGVhY2ggZXhwZXJpbWVudCAKYGBge3J9CmR5LnB1cDEucmVwMS5tYXQgJT4lIGdyb3VwX2J5KGRlZ3JvbiwgdHJlYXRtZW50KSAlPiUgdGFsbHkoKQpgYGAKI2NyZWF0aW5nIHRoZSBkZiBmb3IgdGhlIE1MUgpgYGB7cn0KbWxyLmRmIDwtIGR5LnB1cDEucmVwMS5tYXQgJT4lIAogICNsZWZ0IGpvaW4gd2l0aCB0aGUgZGYgd2l0aCBjZWxsdWxhciBhdHRyaWJ1dGVzCiAgbGVmdF9qb2luKC4scHVwMS5wcm9JbmhpLmF0dHIsIGJ5ID0gYygiY2VsbC5pZCIsInJlZCIsInRyZWF0bWVudCIsImRlZ3JvbiIsICJleHAuZmllbGQiLCJjb2xvbnkiKSkgJT4lIAogICNyZW1vdmUgY2VsbHMgd2l0aCBubyByZnAgcHVuY3RhIGluZm8gCiAgbXV0YXRlKHJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEgPSBpZmVsc2UoaXMubmEocmZwLm1lYW4uYmcuc3ViLnB1bmN0YSksIDAsIHJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEpKSAlPiUgCiAgZmlsdGVyKHJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEgPiAwKQpgYGAKCiNjaGVja2luZyBob3cgbWFueSBjZWxscyB0aGVyZSBhcmUgaW4gZWFjaCBleHBlcmltZW50IApgYGB7cn0KbWxyLmRmICU+JSBncm91cF9ieShkZWdyb24sIHRyZWF0bWVudCkgJT4lIHRhbGx5KCkKYGBgCiNsb29raW5nIHRoZSBwbGFjZW1lbnQgb2Ygc2luZ2xlIGNlbGxzIGluIGltYWdlcwpgYGB7cn0KbWxyLmRmICU+JSAKICBmaWx0ZXIoKQogIGdncGxvdCguLGFlcyh4ID0gcG9zLngsIHkgPSBwb3MueSkpKwogIGdlb21fcG9pbnQoKSsKICBmYWNldF93cmFwKH5kZWdyb24pCmBgYAojI1JlbW92aW5nIHRoZSBjb2x1bW5zIHRoYXQgSSB3b250IHJlZ3Jlc3MgdXBvbgpgYGB7cn0KbWxyLmRmIDwtIG1sci5kZiAlPiUgCiAgZmlsdGVyKHBvcy54ID4gNDUgJiBwb3MueCA8IDExNTAsCiAgcG9zLnkgPiA0NSAmIHBvcy55IDwgMTAwMCkgJT4lCiAgZHBseXI6OnNlbGVjdCgtZiwgCiAgICAgICAgIC1yZnAubWVhbi5hZi5zdWIucHVuY3RhLAogICAgICAgICAtcmZwLnN1bS5hZi5zdWIucHVuY3RhLCAKICAgICAgICAgLWRhcGkuc3VtLmFmLnN1Yi5wdW5jdGEsCiAgICAgICAgIC1kYXBpLm1lYW4uYWYuc3ViLnB1bmN0YSwKICAgICAgICAgLW1vZGVsLCAKICAgICAgICAgLWssCiAgICAgICAgIC1mZXZhbHMsCiAgICAgICAgIC1nZXZhbHMsIAogICAgICAgICAtbml0ZXIsIAogICAgICAgICAtY29udmNvZGUsIAogICAgICAgICAta2t0MSwKICAgICAgICAgLWtrdDIsCiAgICAgICAgIC12YWx1ZSwKICAgICAgICAgLXh0aW1lLCAKICAgICAgICAgIyAtdHJlYXRtZW50LAogICAgICAgICAtcmZwLm1lYW4uYmcuc3ViLAogICAgICAgICAtcmZwLnN1bS5iZy5zdWIsCiAgICAgICAgIC1kYXBpLm1lYW4uYmcuc3ViLAogICAgICAgICAtZGFwaS5zdW0uYmcuc3ViLAogICAgICAgICAtZGFwaS5tZWFuLmJnLnN1Yi5wdW5jdGEsCiAgICAgICAgIC1hcmVhLnB1bmN0YSwKICAgICAgICAgLUJCX0IsCiAgICAgICAgIC1CQl9DLAogICAgICAgICAtcG9zLngsCiAgICAgICAgIC1wb3MueSwKICAgICAgICAgLWdmcC5zdW0uYmcuYWYuc3ViLAogICAgICAgICAtcmZwLnN1bS5iZy5zdWIucHVuY3RhLAogICAgICAgICAtbm8ub2Yudm94ZWxzLAogICAgICAgICAtdm9sdW1lLAogICAgICAgICAtc3BoZXJhY2l0eSkgJT4lIAogIG11dGF0ZShzaGFwZSA9IEVsaXBfQi9FbGlwX0MsIAogICAgICAgICB0LmhhbGYgPSBsb2coMikvZHkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBkcGx5cjo6c2VsZWN0KC1jZWxsLmlkLCAKICAgICAgICAgICAgICAgIC1yZWQsCiAgICAgICAgICAgICAgICAtZXhwLmZpZWxkLCAKICAgICAgICAgICAgICAgIC1haWMsCiAgICAgICAgICAgICAgICAtRWxpcF9CLAogICAgICAgICAgICAgICAgLUVsaXBfQywgCiAgICAgICAgICAgICAgICAtZXhwKSAKYGBgCgojUmVncmVzc29ycyB0byB1c2UgZm9yIE1MUgpgYGB7cn0KcmVncmVzc29ycyA8LSBjKCJkbSIsCiAgICAgICAgICAgICAgICAiZ2ZwLm1lYW4uYmcuYWYuc3ViLm5ldyIsCiAgICAgICAgICAgICAgICAjICJnZnAuc3VtLmJnLmFmLnN1YiIsCiAgICAgICAgICAgICAgICAiYXJlYSIsCiAgICAgICAgICAgICAgICAjICJuby5vZi52b3hlbHMiLAogICAgICAgICAgICAgICAgIyAic3BoZXJhY2l0eSIsCiAgICAgICAgICAgICAgICAjICJ2b2x1bWUiLAogICAgICAgICAgICAgICAgInJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEiLAogICAgICAgICAgICAgICAgIyAicmZwLnN1bS5iZy5zdWIucHVuY3RhIiwKICAgICAgICAgICAgICAgICJkYXBpLnN1bS5iZy5zdWIucHVuY3RhIiwKICAgICAgICAgICAgICAgICJzaGFwZSIpCmBgYAoKRnVuY3Rpb24gdG8gZXZhbHVhdGUgc3RlcCBSIApgYGB7cn0Kc3RlcFIuZm4gPC0gZnVuY3Rpb24ocmVnLCBkZiwgcHJ0LmluaC50cnQsIGlkLnZhcikgewogICNnZXQgdGhlIGVzdGltYXRlcwogIHN0ZXBSLmVzdCA8LQogICAgbGFwcGx5KHJlZywgZnVuY3Rpb24oYSkgewogICAgICAjcmVncmVzc29ycyB0byByZW1vdmUgb25lIGJ5IG9uZQogICAgICB0ZW1wLmRmMiA8LSBkZiAlPiUKICAgICAgICBkcGx5cjo6c2VsZWN0KGFsbF9vZihyZWcpLCAKICAgICAgICAgICAgICAgICAgICAgIGRlZ3JvbiwKICAgICAgICAgICAgICAgICAgICAgIHQuaGFsZiwKICAgICAgICAgICAgICAgICAgICAgICMgZHksIAogICAgICAgICAgICAgICAgICAgICAgY29sb255LCAKICAgICAgICAgICAgICAgICAgICAgIHRyZWF0bWVudCkgJT4lICNyZW1vdmVkIHQuaGFsZiBhbmQgcmVwbGFjZWQgd2l0aCBkeQogICAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgICBkcGx5cjo6c2VsZWN0KC1hKQogICAgICAKICAgICAgdGVtcC5kZjIgJT4lCiAgICAgICAgZmlsdGVyKHRyZWF0bWVudCAlaW4lIHBydC5pbmgudHJ0KSAlPiUKICAgICAgICBzcGxpdCguW2lkLnZhcl0pICU+JQogICAgICAgIG1hcCguLCBmdW5jdGlvbihiKSB7CiAgICAgICAgICBsbSh0LmhhbGYgfiAuLAogICAgICAgICAgICAgZGF0YSA9IGIgJT4lIGRwbHlyOjpzZWxlY3QoLWRlZ3JvbiwgLWNvbG9ueSwgLXRyZWF0bWVudCkpICU+JQogICAgICAgICAgICBicm9vbTo6dGlkeSgpCiAgICAgICAgfSkgJT4lCiAgICAgICAgYmluZF9yb3dzKC5pZCA9IGlkLnZhcikgJT4lCiAgICAgICAgbXV0YXRlKHJlbW92ZWQuY29sID0gYSkKICAgICAgCiAgICB9KSAlPiUKICAgIGJpbmRfcm93cygpCiAgCiAgI2dldCB0aGUgc3RhdHMgb2YgdGhlIG1vZGVsCiAgc3RlcFIuZ2xhbmNlIDwtIGxhcHBseShyZWcsIGZ1bmN0aW9uKGEpIHsKICAgIHRlbXAuZGYyIDwtIGRmICU+JQogICAgICBkcGx5cjo6c2VsZWN0KGFsbF9vZihyZWcpLCBkZWdyb24sIHQuaGFsZiwKICAgICAgICAgICAgICAgICAgICAjIGR5LCAKICAgICAgICAgICAgICAgICAgICBjb2xvbnksIHRyZWF0bWVudCkgJT4lICNyZW1vdmVkIHQuaGFsZiBhbmQgcmVwbGFjZWQgd2l0aCBkeQogICAgICBkcGx5cjo6c2VsZWN0KC1hKQogICAgCiAgICB0ZW1wLmRmMiAlPiUKICAgICAgZmlsdGVyKHRyZWF0bWVudCAlaW4lIHBydC5pbmgudHJ0KSAlPiUKICAgICAgc3BsaXQoLltpZC52YXJdKSAlPiUKICAgICAgbWFwKC4sIGZ1bmN0aW9uKGIpIHsKICAgICAgICBsbSh0LmhhbGYgfiAuLAogICAgICAgICAgIGRhdGEgPSBiICU+JSBkcGx5cjo6c2VsZWN0KC1kZWdyb24sLWNvbG9ueSwtdHJlYXRtZW50KSkgJT4lCiAgICAgICAgICBicm9vbTo6Z2xhbmNlKCkKICAgICAgfSkgJT4lCiAgICAgIGJpbmRfcm93cyguaWQgPSBpZC52YXIpICU+JQogICAgICBtdXRhdGUocmVtb3ZlZC5jb2wgPSBhKQogICAgCiAgfSkgJT4lCiAgICBiaW5kX3Jvd3MoKQogIAogICNnZXQgdGhlIGZpdHMKICBzdGVwUi5maXQgPC0gbGFwcGx5KHJlZywgZnVuY3Rpb24oYSkgewogICAgdGVtcC5kZjIgPC0gZGYgJT4lCiAgICAgIGRwbHlyOjpzZWxlY3QoYWxsX29mKHJlZyksIGRlZ3JvbiwgdC5oYWxmLAogICAgICAgICAgICAgICAgICAgICMgZHksIAogICAgICAgICAgICAgICAgICAgIGNvbG9ueSwgdHJlYXRtZW50KSAlPiUgI3JlbW92ZWQgdC5oYWxmIGFuZCByZXBsYWNlZCB3aXRoIGR5CiAgICAgIGRwbHlyOjpzZWxlY3QoLWEpCiAgICAKICAgIHRlbXAuZGYyICU+JQogICAgICBmaWx0ZXIodHJlYXRtZW50ICVpbiUgcHJ0LmluaC50cnQpICU+JQogICAgICBzcGxpdCguW2lkLnZhcl0pICU+JQogICAgICBtYXAoLiwgZnVuY3Rpb24oYikgewogICAgICAgIGxtKHQuaGFsZiB+IC4sCiAgICAgICAgICAgZGF0YSA9IGIgJT4lIGRwbHlyOjpzZWxlY3QoLWRlZ3JvbiwgLWNvbG9ueSwtdHJlYXRtZW50KSkKICAgICAgfSkKICB9KQogIAogICNvdXRwdXQKICBzdGVwUi5saXN0IDwtIGxpc3Qoc3RlcFIuZXN0LAogICAgICAgICAgICAgICAgICAgICBzdGVwUi5nbGFuY2UsCiAgICAgICAgICAgICAgICAgICAgIHN0ZXBSLmZpdCkKICAKICBuYW1lcyhzdGVwUi5saXN0KSA8LSBjKCJzdGVwUi5lc3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgInN0ZXBSLmdsYW5jZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAic3RlcFIuZml0IikKICByZXR1cm4oc3RlcFIubGlzdCkKfQpgYGAKCmZ1bmN0aW9uIHRvIGV2YWx1YXRlIHRoZSBmdWxsIG1vZGVsCmBgYHtyfQpmdWxsTUxSLmZuIDwtIGZ1bmN0aW9uKHJlZ3Jlc3NvcnMsIGRmLCBwcnQuaW5oLnRydCwgaWQudmFyKSB7CiAgI3N0YXRpc3RpY3MKICBmdWxsUi5nbGFuY2UgPC0gZGYgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBmaWx0ZXIodHJlYXRtZW50ICVpbiUgcHJ0LmluaC50cnQpICU+JQogICAgZHBseXI6OnNlbGVjdChhbGxfb2YocmVncmVzc29ycyksIAogICAgICAgICAgICAgICAgICBkZWdyb24sIAogICAgICAgICAgICAgICAgICB0LmhhbGYsCiAgICAgICAgICAgICAgICAgICMgZHksIAogICAgICAgICAgICAgICAgICBjb2xvbnksIAogICAgICAgICAgICAgICAgICB0cmVhdG1lbnQpICU+JSAjcmVtb3ZlZCB0LmhhbGYgYW5kIHJlcGxhY2VkIHdpdGggZHkKICAgIHNwbGl0KC5baWQudmFyXSkgJT4lCiAgICBtYXAoLiwgZnVuY3Rpb24oYikgewogICAgICBsbSh0LmhhbGYgfiAuLAogICAgICAgICBkYXRhID0gYiAlPiUgZHBseXI6OnNlbGVjdCgtZGVncm9uLCAtY29sb255LCAtdHJlYXRtZW50KSkgJT4lCiAgICAgICAgYnJvb206OmdsYW5jZSgpCiAgICB9KSAlPiUKICAgIGJpbmRfcm93cyguaWQgPSBpZC52YXIpICU+JQogICAgbXV0YXRlKHJlbW92ZWQuY29sID0gIm5vbmUiKQogIAogICNlc3RpbWF0ZXMKICBmdWxsUi5lc3QgPC0gZGYgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBmaWx0ZXIodHJlYXRtZW50ICVpbiUgcHJ0LmluaC50cnQpICU+JQogICAgZHBseXI6OnNlbGVjdChhbGxfb2YocmVncmVzc29ycyksIAogICAgICAgICAgICAgICAgICBkZWdyb24sCiAgICAgICAgICAgICAgICAgIHQuaGFsZiwKICAgICAgICAgICAgICAgICAgIyBkeSwgCiAgICAgICAgICAgICAgICAgIGNvbG9ueSwgCiAgICAgICAgICAgICAgICAgIHRyZWF0bWVudCkgJT4lICNyZW1vdmVkIHQuaGFsZiBhbmQgcmVwbGFjZWQgd2l0aCBkeQogICAgc3BsaXQoLltpZC52YXJdKSAlPiUKICAgIG1hcCguLCBmdW5jdGlvbihiKSB7CiAgICAgIGxtKHQuaGFsZiB+IC4sCiAgICAgICAgIGRhdGEgPSBiICU+JSBkcGx5cjo6c2VsZWN0KC1kZWdyb24sIC1jb2xvbnksLXRyZWF0bWVudCkpICU+JQogICAgICAgIGJyb29tOjp0aWR5KCkKICAgIH0pICU+JQogICAgYmluZF9yb3dzKC5pZCA9IGlkLnZhcikgJT4lCiAgICBtdXRhdGUocmVtb3ZlZC5jb2wgPSAibm9uZSIpCiAgCiAgI2ZpdHMKICBmdWxsTUxSLmZpdCA8LSBkZiAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIGZpbHRlcih0cmVhdG1lbnQgJWluJSBwcnQuaW5oLnRydCkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KGFsbF9vZihyZWdyZXNzb3JzKSwgCiAgICAgICAgICAgICAgICAgIGRlZ3JvbiwgCiAgICAgICAgICAgICAgICAgIHQuaGFsZiwKICAgICAgICAgICAgICAgICAgIyBkeSwgCiAgICAgICAgICAgICAgICAgIGNvbG9ueSwgCiAgICAgICAgICAgICAgICAgIHRyZWF0bWVudCkgJT4lICNyZW1vdmVkIHQuaGFsZiBhbmQgcmVwbGFjZWQgd2l0aCBkeQogICAgc3BsaXQoLltpZC52YXJdKSAlPiUKICAgIG1hcCguLCBmdW5jdGlvbihiKSB7CiAgICAgIGxtKHQuaGFsZiB+IC4sCiAgICAgICAgIGRhdGEgPSBiICU+JSBkcGx5cjo6c2VsZWN0KC1kZWdyb24sIC1jb2xvbnksIC10cmVhdG1lbnQpKQogICAgfSkKICAKICAjb3V0cHV0CiAgZnVsbE1MUi5saXN0IDwtIGxpc3QoZnVsbFIuZ2xhbmNlLAogICAgICAgICAgICAgICAgICAgICAgIGZ1bGxSLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICBmdWxsTUxSLmZpdCkKICAKICBuYW1lcyhmdWxsTUxSLmxpc3QpIDwtIGMoImZ1bGxSLmdsYW5jZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJmdWxsUi5lc3QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiZnVsbE1MUi5maXQiKQogIHJldHVybihmdWxsTUxSLmxpc3QpCn0KYGBgCgojZGYgd2hlcmUgdGhlIHR3byBleHBlcmltZW50cyBvZiBjbG4yIGFuZCBzdGFibGUtR0ZQIGFyZSBjbHViYmVkIApgYGB7cn0KbWxyLmRmMiA8LSBtbHIuZGYgJT4lIAogIGZpbHRlcihkZWdyb24gJWluJSBjKCJjbG4yLjMiLCJtT0RDLjIiLCJzdGFibGUuMyIsInN0YWJsZS4yIiwiY2xuMi40IikpICU+JSAKICBtdXRhdGUoZGVncm9uID0gY2FzZV93aGVuKGRlZ3JvbiAlaW4lIGMoImNsbjIuMyIsImNsbjIuMiIsImNsbjIiLCJjbG4yLjQiKSB+ICJ5ZUdGUC1DTE4yIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZ3JvbiAlaW4lIGMoIm1PREMuMiIsICJtT0RDIikgIH4gInllR0ZQLW1PREMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVncm9uICVpbiUgYygic3RhYmxlIiwic3RhYmxlLjIiLCJzdGFibGUuMyIpIH4gInllR0ZQIikpIAogIApgYGAKCnN0ZXAgTUxSIGVzdGltYXRlcyAKI3dpdGhvdXQgdGhlIHByb3RlaW4gaW5oaWJpdGlvbgpgYGB7cn0Kc3RlcFIubGlzdCA8LSBzdGVwUi5mbihyZWcgPSByZWdyZXNzb3JzLCAKICAgICAgICAgZGYgPSBtbHIuZGYyLAogICAgICAgICBwcnQuaW5oLnRydCA9ICJub25lIiwKICAgICAgICBpZC52YXIgPSAiZGVncm9uIikKCmZ1bGxSLmxpc3QgPC0gZnVsbE1MUi5mbihyZWcgPSByZWdyZXNzb3JzLAogICAgICAgICAgICAgICAgICAgICAgICAgZGYgPSBtbHIuZGYyLAogICAgICAgICAgICAgICAgICAgICAgICAgcHJ0LmluaC50cnQgPSAibm9uZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBpZC52YXIgPSAiZGVncm9uIikKYGBgCgoKIzJEIGNvcnJlbGF0aW9uIHBsb3RzCmBgYHtyfQpsYXBwbHkocmVncmVzc29yc1sxXSwgZnVuY3Rpb24oYSl7CiAgbWxyLmRmICU+JSAKICAgIGZpbHRlcih0cmVhdG1lbnQgIT0gIm5vbmUiKSAlPiUgCiAgbXV0YXRlKHQuaGFsZiA9IGxvZygyKS9keSkgJT4lCiAgICAjIGZpbHRlcihkZWdyb24gJWluJSBjKCJzdGFibGUuMiIsInN0YWJsZS4zIikpICU+JSAKICAgICMgZmlsdGVyKCEoZGVncm9uICVpbiUgYygibU9EQyIsImNsbjIuMiIsImNsbjIiLCJzdGFibGUiKSkpICU+JSAKICAgICMgZmlsdGVyKHRyZWF0bWVudCAlaW4lIGMoImRtc28xIiwiZG1zbzIiKSkgJT4lICAlPiUgCiAgICAgIGdncGxvdCguLGFlcyh5ID0gdC5oYWxmLCB4ID0gLltbYV1dKSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICBzdGF0X2NvcigpKwogICAgIyBzdGF0X3JlZ2xpbmVfZXF1YXRpb24oKSsKICAgIGZhY2V0X3dyYXAofnRyZWF0bWVudCAsIHNjYWxlcyA9ICJmcmVlIikrCiAgICBsYWJzKHRpdGxlID0gYSkrCiAgICBzY2FsZV94X2xvZzEwKCkKICAKfSkKCmBgYAoKI3l+eCArIGMgc2luZ2xlIHZhcmlhYmxlIHJlZ3Jlc3Npb24Kc2luZ2xlIHJlZ3Jlc3NvciBzdGF0aXN0aWNzCmBgYHtyfQpzdGVwUi4xdmFyIDwtIGxhcHBseShyZWdyZXNzb3JzLCBmdW5jdGlvbihhKXsKICB0ZW1wLmRmMiA8LSBtbHIuZGYgJT4lIAogICAgdW5ncm91cCgpICU+JSAKICAgIGRwbHlyOjpzZWxlY3QoYSwgdC5oYWxmLGRlZ3JvbikKICAKICB0ZW1wLmRmMiAlPiUgCiAgICBzcGxpdCguJGRlZ3JvbikgJT4lIAogICAgbWFwKC4sZnVuY3Rpb24oYil7CiAgICAgIGxtKHQuaGFsZiB+IC4sIGRhdGEgPSBiICU+JSBkcGx5cjo6c2VsZWN0KC1kZWdyb24pKSAlPiUgCiAgICAgICAgYnJvb206OmdsYW5jZSgpCiAgICB9KSAlPiUgCiAgICBiaW5kX3Jvd3MoLmlkID0gImRlZ3JvbiIpICU+JSAKICAgIG11dGF0ZShzaW5nbGUuY29sID0gYSkKICAgCn0pICU+JSAKICBiaW5kX3Jvd3MoKQpgYGAKCnNpbmdsZSByZWdyZXNzb3IgZXN0aW1hdGVzIApgYGB7cn0Kc3RlcFIuMXZhci5lc3QgPC0gbGFwcGx5KHJlZ3Jlc3NvcnMsIGZ1bmN0aW9uKGEpewogIHRlbXAuZGYyIDwtIHRlbXAuZGYgJT4lIAogICAgdW5ncm91cCgpICU+JSAKICAgIGRwbHlyOjpzZWxlY3QoYSwgdC5oYWxmLGRlZ3JvbikKICAKICB0ZW1wLmRmMiAlPiUgCiAgICBzcGxpdCguJGRlZ3JvbikgJT4lIAogICAgbWFwKC4sZnVuY3Rpb24oYil7CiAgICAgIGxtKHQuaGFsZiB+IC4sIGRhdGEgPSBiICU+JSBkcGx5cjo6c2VsZWN0KC1kZWdyb24pKSAlPiUgCiAgICAgICAgYnJvb206OnRpZHkoKQogICAgfSkgJT4lIAogICAgYmluZF9yb3dzKC5pZCA9ICJkZWdyb24iKSAlPiUgCiAgICBtdXRhdGUoc2luZ2xlLmNvbCA9IGEpCiAgIAp9KSAlPiUgCiAgYmluZF9yb3dzKCkKCiNmaXRzCnN0ZXBSLjF2YXIuZml0IDwtIGxhcHBseShyZWdyZXNzb3JzLCBmdW5jdGlvbihhKXsKICB0ZW1wLmRmMiA8LSBtbHIuZGYgJT4lIAogICAgdW5ncm91cCgpICU+JSAKICAgIGRwbHlyOjpzZWxlY3QoYSwgdC5oYWxmLGRlZ3JvbikKICAKICB0ZW1wLmRmMiAlPiUgCiAgICBzcGxpdCguJGRlZ3JvbikgJT4lIAogICAgbWFwKC4sZnVuY3Rpb24oYil7CiAgICAgIGxtKHQuaGFsZiB+IC4sIGRhdGEgPSBiICU+JSBkcGx5cjo6c2VsZWN0KC1kZWdyb24pKSAKICAgIH0pIAp9KSAKYGBgCgojdGVzdGluZyBmb3Igb25lIGRlZ3JvbgpgYGB7cn0KY2xuMi4zLmRmIDwtIHRlbXAuZGYgJT4lIAogIGZpbHRlcihkZWdyb24gPT0gImNsbjIuMyIpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIHNlbGVjdCgtZHksLWRlZ3JvbikKCmxtKHQuaGFsZiB+IGdmcC5tZWFuLmJnLmFmLnN1Yi5uZXcgCiAgICsgcmZwLnN1bS5iZy5zdWIucHVuY3RhIAogICArIGFyZWEgCiAgIC0gbm8ub2Yudm94ZWxzIAogICAtIGRhcGkuc3VtLmJnLnN1Yi5wdW5jdGEgCiAgICsgc3BoZXJhY2l0eQogICArIHNoYXBlCiAgICsgdm9sdW1lCiAgICAgLCBkYXRhID0gY2xuMi4zLmRmICkgJT4lIAogIHN1bW1hcnkoKQpgYGAKCiNwbG90dGluZyB0aGUgZGlmZmVyZW5jZSBpbiByMiAoZnVsbCBtb2RlbCAtIGRyb3BvdXQgbW9kZWwpCmBgYHtyfQpkZWx0YVIyLnBsdC5hbGwgPC0gYmluZF9yb3dzKGZ1bGxSLmxpc3QkZnVsbFIuZ2xhbmNlLCBzdGVwUi5saXN0JHN0ZXBSLmdsYW5jZSkgJT4lCiAgICBtdXRhdGUoYWRqLnIuc3F1YXJlZCA9IHJvdW5kKGFkai5yLnNxdWFyZWQgLCBkaWdpdHMgPSA0KSkgJT4lIAogICMgc2VwYXJhdGUoLixkZWdyb24sIGludG8gPSBjKCJkZWdyb24iLCJjb2xvbnkiKSwgc2VwID0gIi5SZXBsaWNhdGUgIikgJT4lICAKICAgIyBmaWx0ZXIocC52YWx1ZSA8IDAuMDUpICU+JSAKICAjIGdyb3VwX2J5KGRlZ3JvbiwgcmVtb3ZlZC5jb2wpICU+JSAKICBkcGx5cjo6c2VsZWN0KGRlZ3Jvbiwgci5zcXVhcmVkLCByZW1vdmVkLmNvbCkgJT4lIAogIHBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gci5zcXVhcmVkLCBuYW1lc19mcm9tID0gcmVtb3ZlZC5jb2wpICU+JSAKICByZW5hbWUoIlJhdGUgb2YgTWF0dXJhdGlvbiIgPSAiZG0iLCAKICAgICAgICAgIkdGUCIgPSAiZ2ZwLm1lYW4uYmcuYWYuc3ViLm5ldyIsCiAgICAgICAgICJBcmVhIiA9ICJhcmVhIiwKICAgICAgICAgIlB1cDEtdERpbWVyMiIgPSAicmZwLm1lYW4uYmcuc3ViLnB1bmN0YSIsCiAgICAgICAgICJEQVBJIiA9ICJkYXBpLnN1bS5iZy5zdWIucHVuY3RhIiwKICAgICAgICAgIlNoYXBlIiA9ICJzaGFwZSIpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IDM6OCkgJT4lIAogIG11dGF0ZSh2YWx1ZS5yYXRpbyA9IHZhbHVlLyBub25lLAogICAgICAgICB2YWx1ZS5zdWIgPSBub25lIC0gdmFsdWUpICU+JSAKICAjIGZpbHRlcihkZWdyb24gJWluJSBjKCJjbG4yLjMiLCJtT0RDLjIiLCJzdGFibGUuMyIsInN0YWJsZS4yIiwiY2xuMi40IikpICU+JSAKICAjIG11dGF0ZShkZWdyb24gPSBjYXNlX3doZW4oZGVncm9uICVpbiUgYygiY2xuMi4zIiwiY2xuMi4yIiwiY2xuMiIsImNsbjIuNCIpIH4gIkdGUC1DTE4yIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVncm9uICVpbiUgYygibU9EQy4yIiwgIm1PREMiKSAgfiAiR0ZQLW1PREMiLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWdyb24gJWluJSBjKCJzdGFibGUiLCJzdGFibGUuMiIsInN0YWJsZS4zIikgfiAieWVHRlAiKSwKICAjICAgICAgICBkZWdyb24gPSBmYWN0b3IoZGVncm9uICwgbGV2ZWxzID0gYygiR0ZQLW1PREMiLCJHRlAtQ0xOMiIsInllR0ZQIikpKSAlPiUKICBtdXRhdGUoZGVncm9uID0gZmFjdG9yKGRlZ3JvbiAsIGxldmVscyA9IGMoInllR0ZQLW1PREMiLCJ5ZUdGUC1DTE4yIiwieWVHRlAiKSkpICU+JSAKICBnZ3Bsb3QoLixhZXMoeSA9IG5hbWUsIHggPSB2YWx1ZS5zdWIpKSsKICBnZW9tX2NvbCh3aWR0aCA9IDAuMikrCiAgZmFjZXRfd3JhcCh+ZGVncm9uLCBzY2FsZXMgPSAiZnJlZSIpKwogIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gZnVuY3Rpb24oeCkgc3RyX3dyYXAoeCwgd2lkdGggPSAxMCkpKwogIHhsYWIoVGVYKCIkRGVsdGEocl57Mn1fe2Z1bGx9IC0gcl57Mn1fe3N0ZXB9KSIpKSsKICB5bGFiKCJSZWdyZXNzb3IgRHJvcHBlZCIpKwogIHRoZW1lX3B1YnIoKSsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwKSkKCmRlbHRhUjIucGx0LmFsbApgYGAKCiN0cmFuc2Zvcm0gZG0gYW5kIGRhcGkgaW50ZW5zaXR5CmBgYHtyfQpzdGVwUi5saXN0LnRyYW5zIDwtIHN0ZXBSLmZuKHJlZyA9IHJlZ3Jlc3NvcnMsIAogICAgICAgICBkZiA9IG1sci5kZjIgJT4lIAogICAgICAgICAgIG11dGF0ZShkbSA9IGxvZzEwKGRtKSksCiAgICAgICAgIHBydC5pbmgudHJ0ID0gIm5vbmUiLAogICAgICAgIGlkLnZhciA9ICJkZWdyb24iKQoKZnVsbFIubGlzdC50cmFucyA8LSBmdWxsTUxSLmZuKHJlZyA9IHJlZ3Jlc3NvcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICBkZiA9IG1sci5kZjIgJT4lIAogICAgICAgICAgIG11dGF0ZShkbSA9IGxvZzEwKGRtKSksCiAgICAgICAgICAgICAgICAgICAgICAgICBwcnQuaW5oLnRydCA9ICJub25lIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGlkLnZhciA9ICJkZWdyb24iKQpgYGAKCmBgYHtyfQpiaW5kX3Jvd3MoZnVsbFIubGlzdC50cmFucyRmdWxsUi5nbGFuY2UsIHN0ZXBSLmxpc3QudHJhbnMkc3RlcFIuZ2xhbmNlKSAlPiUKICAgIG11dGF0ZShhZGouci5zcXVhcmVkID0gcm91bmQoYWRqLnIuc3F1YXJlZCAsIGRpZ2l0cyA9IDQpKSAlPiUgCiAgc2VsZWN0KGRlZ3Jvbiwgci5zcXVhcmVkLCByZW1vdmVkLmNvbCkgJT4lIAogIHBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gci5zcXVhcmVkLCBuYW1lc19mcm9tID0gcmVtb3ZlZC5jb2wpICU+JSAKICByZW5hbWUoIlJhdGUgb2YgTWF0dXJhdGlvbiIgPSAiZG0iLCAKICAgICAgICAgIkdGUCBpbnRlbnNpdHkiID0gImdmcC5tZWFuLmJnLmFmLnN1Yi5uZXciLAogICAgICAgICAiQXJlYSIgPSAiYXJlYSIsCiAgICAgICAgICJQdXAxLXREaW1lciIgPSAicmZwLm1lYW4uYmcuc3ViLnB1bmN0YSIsCiAgICAgICAgICJUb3RhbCBEQVBJIEludC4iID0gImRhcGkuc3VtLmJnLnN1Yi5wdW5jdGEiLAogICAgICAgICAiQ2VsbHVsYXIgU2hhcGUiID0gInNoYXBlIikgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gMzo4KSAlPiUgCiAgbXV0YXRlKHZhbHVlLnJhdGlvID0gdmFsdWUvIG5vbmUsCiAgICAgICAgIHZhbHVlLnN1YiA9IG5vbmUgLSB2YWx1ZSkgJT4lIAogICMgZmlsdGVyKGRlZ3JvbiAlaW4lIGMoImNsbjIuMyIsIm1PREMuMiIsInN0YWJsZS4zIiwic3RhYmxlLjIiLCJjbG4yLjQiKSkgJT4lIAogICMgbXV0YXRlKGRlZ3JvbiA9IGNhc2Vfd2hlbihkZWdyb24gJWluJSBjKCJjbG4yLjMiLCJjbG4yLjIiLCJjbG4yIiwiY2xuMi40IikgfiAiR0ZQLUNMTjIiLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWdyb24gJWluJSBjKCJtT0RDLjIiLCAibU9EQyIpICB+ICJHRlAtbU9EQyIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZ3JvbiAlaW4lIGMoInN0YWJsZSIsInN0YWJsZS4yIiwic3RhYmxlLjMiKSB+ICJ5ZUdGUCIpLAogICMgICAgICAgIGRlZ3JvbiA9IGZhY3RvcihkZWdyb24gLCBsZXZlbHMgPSBjKCJHRlAtbU9EQyIsIkdGUC1DTE4yIiwieWVHRlAiKSkpICU+JQogIG11dGF0ZShkZWdyb24gPSBmYWN0b3IoZGVncm9uICwgbGV2ZWxzID0gYygiR0ZQLW1PREMiLCJHRlAtQ0xOMiIsInllR0ZQIikpKSAlPiUgCiAgZ2dwbG90KC4sYWVzKHkgPSBuYW1lLCB4ID0gdmFsdWUuc3ViKSkrCiAgZ2VvbV9jb2wod2lkdGggPSAwLjIpKwogIGZhY2V0X3dyYXAofmRlZ3Jvbiwgc2NhbGVzID0gImZyZWUiKSsKICB0aGVtZV9wdWJyKCkrCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksIAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzApKSsKICAjIHNjYWxlX3hfbG9nMTAoKSsKICB4bGFiKFRlWCgiJERlbHRhKHJeezJ9X3tmdWxsfSAtIHJeezJ9X3tzdGVwfSkiKSkrCiAgeWxhYigiUmVncmVzc29yIERyb3BwZWQiKSsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkKCgpgYGAKCiNsb29rIGF0IHRoZSBzaWduIG9mIHRoZSBlc3RpbWF0ZXMgCmBgYHtyfQpmdWxsUi5saXN0LnRyYW5zJGZ1bGxSLmVzdCAlPiUgc3BsaXQoLiRkZWdyb24pCgpsbSh0LmhhbGYgfiByZnAubWVhbi5iZy5zdWIucHVuY3RhICsgZG0gKyBnZnAubWVhbi5iZy5hZi5zdWIubmV3ICsgZGFwaS5zdW0uYmcuc3ViLnB1bmN0YSwgZGF0YSA9IG1sci5kZjIgJT4lIGZpbHRlcihkZWdyb24gPT0gIkdGUC1tT0RDIikpCmBgYAoKI3Jlc2lkdWFsIGFuYWx5c2lzIG9mIHRoZSBtb2RlbHMKYGBge3J9CiNyZXNpZHVhbCBwbG90cyBhZ2FpbnN0IHRoZSBmaXR0ZWQgdmFsdWVzCmZ1bGxNTFIuZml0ICU+JSAKICBtYXAoLixhdXRvcGxvdCkKCgojcmVzaWR1YWwgcGxvdHMgYWdhaW5zdCB0aGUgcmVncmVzc29ycwpmdWxsTUxSLmZpdCAlPiUgCiAgbWFwKC4sZnVuY3Rpb24oYSl7CiAgICBwbHQuZGYgPC0gYSRtb2RlbCAlPiUgCiAgICAgIG11dGF0ZShkbSA9IGxvZzEwKGRtKSwKICAgICAgICByZXMgPSBhJHJlc2lkdWFscykgJT4lIAogICAgICBwaXZvdF9sb25nZXIoY29scyA9IDI6NykKICAgIAogICAgcGx0LmRmICU+JSAKICAgICAgZ2dwbG90KC4sYWVzKHggPSB2YWx1ZSwgeSA9IHJlcykpKwogICAgICBnZW9tX3BvaW50KCkrCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gInJlZDQiKSsKICAgICAgZmFjZXRfd3JhcCh+bmFtZSwgc2NhbGVzID0gImZyZWUiKSsKICAgICAgeGxhYigiUmVncmVzc29yIikrCiAgICAgIHlsYWIoIlJlc2lkdWFscyIpCiAgICAgIAogIH0pCgoKYGBgCk9ic2VydmF0aW9uczogCmZyb20gdGhlIHJlc2lkdWFsIHZzIGZpdHRlZCBwbG90czogCkZvciB0aGUgZGVncm9uIEdGUHMgdGhlIHJlc2lkdWFsIHZzIHRoZSBmaXR0ZWQgcGxvdCBsaWVzIGFyb3VuZCB0aGUgaG9yaXpvbnR0YWwgYmFuZCBhcm91bmQgMC4gCmJ1dCBmb3Igc3RhYmxlIEdGUCwgdGhlIHJlc2lkdWFsIHBsb3QgaXMgYW4gb3BlbiBmdW5uZWwgc2hhcGUuIApBY2NvcmRpbmcgdG8gcGFnZSAxMzkgaW4gdGhlIGludHJvIHRvIGxpbmVhciByZWdyZXNzaW9uOiAKVGhlIHBhdHRlcm5zIGluIHBhbmVscyBiIGFuZCBjIGluZGljYXRlIHRoYXQgdGhlIHZhcmlhbmNlIG9mIHRoZSBlcnJvcnMgaXMgbm90IGNvbnN0YW50LiBUaGUgb3V0d2FyZC1vcGVuaW5nIGZ1bm5lbCBwYXR0ZXJuIGluIHBhbmVsIGIgaW1wbGllcyB0aGF0IHRoZSB2YXJpYW5jZSBpcyBhbiBpbmNyZWFzaW5nIGZ1bmN0aW9uIG9mIHkuIApGcm9tIHRoZSByZXNpZHVhbHMgdnMgcmVncmVzc29ycyBwbG90czoKaW4geWVHRlA6IHRoZXJlIGlzIGEgc3Ryb25nIGZ1bm5lbCBzaGFwZSB3aXRoIHRoZSBHRlAgaW50ZW5zaXR5OiByZXNpZHVhbHMgaXMgbmVnYXRpdmVseSByZWxhdGVkIHRvIHRoZSBHRlAgaW50ZW5zaXR5LiAKCiN0LmhhbGYgdnMgZG0gCmBgYHtyfQptbHIuZGYgJT4lIAogIGdncGxvdCguLGFlcyh4ID0gZG0sIHkgPSBkeSkpKwogIGdlb21fcG9pbnQoKSsKICBmYWNldF93cmFwKH5kZWdyb24sIHNjYWxlcyA9ICJmcmVlIikrCiAgc2NhbGVfeF9sb2cxMCgpCmBgYAoKdGVzdGluZyBtdWx0aXBsZSBjb2xpbmVhcml0eSB1c2luZyB0aGUgZnVsbCBtb2RlbCAKbWV0aG9kID0gdmFyaWFuY2UgaW5mbGF0aW9uIGZhY3RvcnMuIHZpZiA+IDUgZm9yIGEgcmVncmVzc29yIGlzIHByb2JsZW1hdGljCmBgYHtyfQpsaWJyYXJ5KGNhcikKCmZ1bGxSLmxpc3QkZnVsbE1MUi5maXQgJT4lIG1hcCguLHZpZikKCmBgYAoKI29ubHkgdGhlIGdmcCwgcmZwLCBkYXBpIHJlZ3Jyc3NvcnMgCmBgYHtyfQpyZWdyZXNzb3JzLmZwIDwtIGMoImdmcC5tZWFuLmJnLmFmLnN1Yi5uZXciLAogICAgICAgICAgICAgICAgICAgInJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEiLAogICAgICAgICAgICAgICAgICAgImRhcGkuc3VtLmJnLnN1Yi5wdW5jdGEiKQoKc3RlcFIuZnAubGlzdCA8LSBzdGVwUi5mbihyZWcgPSByZWdyZXNzb3JzLmZwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBkZiA9IG1sci5kZjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJ0LmluaC50cnQgPSAibm9uZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaWQudmFyID0gImRlZ3JvbiIpCgpmdWxsUi5mcC5saXN0IDwtIGZ1bGxNTFIuZm4ocmVncmVzc29ycyA9IHJlZ3Jlc3NvcnMuZnAsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGRmID0gbWxyLmRmMiwKICAgICAgICAgICAgICAgICAgICAgICAgICBwcnQuaW5oLnRydCA9ICJub25lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBpZC52YXIgPSAiZGVncm9uIikKYGBgCgojdmFyaWFuY2UgaW5mbGF0aW9uIGZhY3RvcgpgYGB7cn0KdmlmKGZ1bGwuZnAuZml0JGNsbjIuMykgCnZpZihmdWxsLmZwLmZpdCRjbG4yLjQpIAp2aWYoZnVsbC5mcC5maXQkbU9EQy4yKSAKdmlmKGZ1bGwuZnAuZml0JHN0YWJsZS4zKQp2aWYoZnVsbC5mcC5maXQkc3RhYmxlLjIpIApgYGAKCiNkZWx0YSByMiBmb3Igb25seSB0aGUgZmx1b3Jlc2NlbnQgcHJvdGVpbnMgYXMgdGhlIHJlZ3Jlc3NvcnMKYGBge3J9CmRlbHRhUjIucGx0IDwtIGJpbmRfcm93cyhmdWxsUi5mcC5saXN0JGZ1bGxSLmdsYW5jZSwgc3RlcFIuZnAubGlzdCRzdGVwUi5nbGFuY2UpICU+JQogICAgbXV0YXRlKGFkai5yLnNxdWFyZWQgPSByb3VuZChhZGouci5zcXVhcmVkICwgZGlnaXRzID0gNCkpICU+JSAKICAjIHNlcGFyYXRlKC4sZGVncm9uLCBpbnRvID0gYygiZGVncm9uIiwiY29sb255IiksIHNlcCA9ICIuUmVwbGljYXRlICIpICU+JSAgCiAgICMgZmlsdGVyKHAudmFsdWUgPCAwLjA1KSAlPiUgCiAgIyBncm91cF9ieShkZWdyb24sIHJlbW92ZWQuY29sKSAlPiUgCiAgZHBseXI6OnNlbGVjdChkZWdyb24sIHIuc3F1YXJlZCwgcmVtb3ZlZC5jb2wpICU+JSAKICBwaXZvdF93aWRlcih2YWx1ZXNfZnJvbSA9IHIuc3F1YXJlZCwgbmFtZXNfZnJvbSA9IHJlbW92ZWQuY29sKSAlPiUgCiAgcmVuYW1lKCJHRlAgaW50ZW5zaXR5IiA9ICJnZnAubWVhbi5iZy5hZi5zdWIubmV3IiwKICAgICAgICAgIlB1cDEtdERpbWVyIiA9ICJyZnAubWVhbi5iZy5zdWIucHVuY3RhIiwKICAgICAgICAgIlRvdGFsIERBUEkgSW50LiIgPSAiZGFwaS5zdW0uYmcuc3ViLnB1bmN0YSIpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IDM6NSkgJT4lIAogIG11dGF0ZSh2YWx1ZS5yYXRpbyA9IHZhbHVlLyBub25lLAogICAgICAgICB2YWx1ZS5zdWIgPSBub25lIC0gdmFsdWUpICU+JSAKICAjIGZpbHRlcihkZWdyb24gJWluJSBjKCJjbG4yLjMiLCJtT0RDLjIiLCJzdGFibGUuMyIsInN0YWJsZS4yIiwiY2xuMi40IikpICU+JSAKICAjIG11dGF0ZShkZWdyb24gPSBjYXNlX3doZW4oZGVncm9uICVpbiUgYygiY2xuMi4zIiwiY2xuMi4yIiwiY2xuMiIsImNsbjIuNCIpIH4gIkdGUC1DTE4yIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVncm9uICVpbiUgYygibU9EQy4yIiwgIm1PREMiKSAgfiAiR0ZQLW1PREMiLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWdyb24gJWluJSBjKCJzdGFibGUiLCJzdGFibGUuMiIsInN0YWJsZS4zIikgfiAieWVHRlAiKSwKICAjICAgICAgICBkZWdyb24gPSBmYWN0b3IoZGVncm9uICwgbGV2ZWxzID0gYygiR0ZQLW1PREMiLCJHRlAtQ0xOMiIsInllR0ZQIikpKSAlPiUKICBtdXRhdGUoZGVncm9uID0gZmFjdG9yKGRlZ3JvbiAsIGxldmVscyA9IGMoInllR0ZQLW1PREMiLCJ5ZUdGUC1DTE4yIiwieWVHRlAiKSkpICU+JSAKICBnZ3Bsb3QoLixhZXMoeSA9IG5hbWUsIHggPSB2YWx1ZS5zdWIpKSsKICBnZW9tX2NvbCh3aWR0aCA9IDAuMikrCiAgZmFjZXRfd3JhcCh+ZGVncm9uLCBzY2FsZXMgPSAiZnJlZSIpKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKSsKICAjIHNjYWxlX3hfbG9nMTAoKSsKICB4bGFiKFRlWCgiJERlbHRhKHJeezJ9X3tmdWxsfSAtIHJeezJ9X3tzdGVwfSkiKSkrCiAgeWxhYigiUmVncmVzc29yIERyb3BwZWQiKSsKICB0aGVtZV9wdWJyKCkrCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpCgpkZWx0YVIyLnBsdApgYGAKI3Jlc3BvbnNlID09IGR5IGluc3RlYWQgb2YgdC5oYWxmIApgYGB7cn0KYmluZF9yb3dzKGZ1bGxSLmZwLmxpc3QkZnVsbFIuZ2xhbmNlLCBzdGVwUi5mcC5saXN0JHN0ZXBSLmdsYW5jZSkgJT4lCiAgICBtdXRhdGUoYWRqLnIuc3F1YXJlZCA9IHJvdW5kKGFkai5yLnNxdWFyZWQgLCBkaWdpdHMgPSA0KSkgJT4lIAogICMgc2VwYXJhdGUoLixkZWdyb24sIGludG8gPSBjKCJkZWdyb24iLCJjb2xvbnkiKSwgc2VwID0gIi5SZXBsaWNhdGUgIikgJT4lICAKICAgZmlsdGVyKHAudmFsdWUgPCAwLjA1KSAlPiUgCiAgIyBncm91cF9ieShkZWdyb24sIHJlbW92ZWQuY29sKSAlPiUgCiAgc2VsZWN0KGRlZ3Jvbiwgci5zcXVhcmVkLCByZW1vdmVkLmNvbCkgJT4lIAogIHBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gci5zcXVhcmVkLCBuYW1lc19mcm9tID0gcmVtb3ZlZC5jb2wpICU+JSAKICByZW5hbWUoIkdGUCBpbnRlbnNpdHkiID0gImdmcC5tZWFuLmJnLmFmLnN1Yi5uZXciLAogICAgICAgICAiUHVwMS10RGltZXIiID0gInJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEiLAogICAgICAgICAiVG90YWwgREFQSSBJbnQuIiA9ICJkYXBpLnN1bS5iZy5zdWIucHVuY3RhIikgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gMzo1KSAlPiUgCiAgbXV0YXRlKHZhbHVlLnJhdGlvID0gdmFsdWUvIG5vbmUsCiAgICAgICAgIHZhbHVlLnN1YiA9IG5vbmUgLSB2YWx1ZSkgJT4lIAogICBmaWx0ZXIoZGVncm9uICVpbiUgYygiY2xuMi4zIiwibU9EQy4yIiwic3RhYmxlLjMiLCJzdGFibGUuMiIsImNsbjIuNCIpKSAlPiUgCiAgIyBtdXRhdGUoZGVncm9uID0gY2FzZV93aGVuKGRlZ3JvbiAlaW4lIGMoImNsbjIuMyIsImNsbjIuMiIsImNsbjIiLCJjbG4yLjQiKSB+ICJHRlAtQ0xOMiIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlZ3JvbiAlaW4lIGMoIm1PREMuMiIsICJtT0RDIikgIH4gIkdGUC1tT0RDIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVncm9uICVpbiUgYygic3RhYmxlIiwic3RhYmxlLjIiLCJzdGFibGUuMyIpIH4gInllR0ZQIiksCiAgIyAgICAgICAgZGVncm9uID0gZmFjdG9yKGRlZ3JvbiAsIGxldmVscyA9IGMoIkdGUC1tT0RDIiwiR0ZQLUNMTjIiLCJ5ZUdGUCIpKSkgJT4lCiAgIyBtdXRhdGUoZGVncm9uID0gZmFjdG9yKGRlZ3JvbiAsIGxldmVscyA9IGMoIkdGUC1tT0RDIiwiR0ZQLUNMTjIiLCJ5ZUdGUCIpKSkgJT4lIAogIGdncGxvdCguLGFlcyh5ID0gbmFtZSwgeCA9IHZhbHVlLnN1YikpKwogIGdlb21fY29sKHdpZHRoID0gMC4yKSsKICBmYWNldF93cmFwKH5kZWdyb24sIHNjYWxlcyA9ICJmcmVlIikrCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpKwogICMgc2NhbGVfeF9sb2cxMCgpKwogIHhsYWIoVGVYKCIkRGVsdGEocl57Mn1fe2Z1bGx9IC0gcl57Mn1fe3N0ZXB9KSIpKSsKICB5bGFiKCJSZWdyZXNzb3IgRHJvcHBlZCIpKwogIHRoZW1lX3B1YnIoKSsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkKYGBgCgoKI1dpdGggdGhlIHByb3RlaW4gaW5oaWJpdG9ycwpgYGB7cn0KI3dpdGggNiByZWdyZXNzb3JzCnN0ZXBSLnBydEluaC5saXN0IDwtIHN0ZXBSLmZuKHJlZyA9IHJlZ3Jlc3NvcnMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZiA9IG1sci5kZiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBydC5pbmgudHJ0ID0gYygiZG1zbzEiLCJkbXNvMiIsIjF1TSIsIjIuNXVNIiwiNXVNIiwiNTB1TSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQudmFyID0gInRyZWF0bWVudCIpCmZ1bGxSLnBydEluaC5saXN0IDwtIGZ1bGxNTFIuZm4ocmVnID0gcmVncmVzc29ycywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRmID0gbWxyLmRmLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJ0LmluaC50cnQgPSBjKCJkbXNvMSIsImRtc28yIiwiMXVNIiwiMi41dU0iLCI1dU0iLCI1MHVNIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZC52YXIgPSAidHJlYXRtZW50IikKCiN3aXRoIGp1c3QgZmx1b3JlY2VudCBwcm90ZWlucwpzdGVwUi5wcnRJbmguZnAubGlzdCA8LSBzdGVwUi5mbihyZWcgPSByZWdyZXNzb3JzLmZwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGYgPSBtbHIuZGYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcnQuaW5oLnRydCA9IGMoImRtc28xIiwiZG1zbzIiLCIxdU0iLCIyLjV1TSIsIjV1TSIsIjUwdU0iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkLnZhciA9ICJ0cmVhdG1lbnQiKQpmdWxsUi5wcnRJbmguZnAubGlzdCA8LSBmdWxsTUxSLmZuKHJlZyA9IHJlZ3Jlc3NvcnMuZnAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZiA9IG1sci5kZiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBydC5pbmgudHJ0ID0gYygiZG1zbzEiLCJkbXNvMiIsIjF1TSIsIjIuNXVNIiwiNXVNIiwiNTB1TSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWQudmFyID0gInRyZWF0bWVudCIpCgpgYGAKCnBsb3RzCmBgYHtyfQojd2l0aCA2IHJlZ3Jlc3NvcnMKYmluZF9yb3dzKGZ1bGxSLnBydEluaC5saXN0JGZ1bGxSLmdsYW5jZSwgc3RlcFIucHJ0SW5oLmxpc3Qkc3RlcFIuZ2xhbmNlKSAlPiUKICAgIG11dGF0ZShhZGouci5zcXVhcmVkID0gcm91bmQoYWRqLnIuc3F1YXJlZCAsIGRpZ2l0cyA9IDQpKSAlPiUgCiAgc2VsZWN0KHRyZWF0bWVudCwgci5zcXVhcmVkLCByZW1vdmVkLmNvbCkgJT4lIAogIHBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gci5zcXVhcmVkLCBuYW1lc19mcm9tID0gcmVtb3ZlZC5jb2wpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IDM6OCkgJT4lIAogIG11dGF0ZSh2YWx1ZS5yYXRpbyA9IHZhbHVlLyBub25lLAogICAgICAgICB2YWx1ZS5zdWIgPSBub25lIC0gdmFsdWUpICU+JSAKICBnZ3Bsb3QoLixhZXMoeSA9IG5hbWUsIHggPSB2YWx1ZS5zdWIpKSsKICBnZW9tX2NvbCgpKwogIGZhY2V0X3dyYXAofmZhY3Rvcih0cmVhdG1lbnQsIGxldmVscyA9IGMoImRtc28xIiwiZG1zbzIiLCIxdU0iLCIyLjV1TSIsIjV1TSIsIjUwdU0iKSksIHNjYWxlcyA9ICJmcmVlIikrCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpKwogICMgc2NhbGVfeF9sb2cxMCgpKwogIHhsYWIoVGVYKCIkRGVsdGEocl57Mn1fe2Z1bGx9IC0gcl57Mn1fe3N0ZXB9KSIpKSsKICB5bGFiKCJyZWdyZXNzb3IgZHJvcHBlZCIpCgojd2l0aCAzIGZsdW9yZXNjZW50IHByb3RlaW5zCmJpbmRfcm93cyhmdWxsUi5wcnRJbmguZnAubGlzdCRmdWxsUi5nbGFuY2UsIHN0ZXBSLnBydEluaC5mcC5saXN0JHN0ZXBSLmdsYW5jZSkgJT4lCiAgICBtdXRhdGUoYWRqLnIuc3F1YXJlZCA9IHJvdW5kKGFkai5yLnNxdWFyZWQgLCBkaWdpdHMgPSA0KSkgJT4lIAogIHNlbGVjdCh0cmVhdG1lbnQsIHIuc3F1YXJlZCwgcmVtb3ZlZC5jb2wpICU+JSAKICBwaXZvdF93aWRlcih2YWx1ZXNfZnJvbSA9IHIuc3F1YXJlZCwgbmFtZXNfZnJvbSA9IHJlbW92ZWQuY29sKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAzOjUpICU+JSAKICBtdXRhdGUodmFsdWUucmF0aW8gPSB2YWx1ZS8gbm9uZSwKICAgICAgICAgdmFsdWUuc3ViID0gbm9uZSAtIHZhbHVlKSAlPiUgCiAgZ2dwbG90KC4sYWVzKHkgPSBuYW1lLCB4ID0gdmFsdWUuc3ViKSkrCiAgZ2VvbV9jb2woKSsKICBmYWNldF93cmFwKH5mYWN0b3IodHJlYXRtZW50LCBsZXZlbHMgPSBjKCJkbXNvMSIsImRtc28yIiwiMXVNIiwiMi41dU0iLCI1dU0iLCI1MHVNIikpLCBzY2FsZXMgPSAiZnJlZSIpKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKSsKICAjIHNjYWxlX3hfbG9nMTAoKSsKICB4bGFiKFRlWCgiJERlbHRhKHJeezJ9X3tmdWxsfSAtIHJeezJ9X3tzdGVwfSkiKSkrCiAgeWxhYigicmVncmVzc29yIGRyb3BwZWQiKQpgYGAKCiNsb29rZWQgYXQgdGhlIG91dGxpZXJzCmBgYHtyfQppbnN0YWxsLnBhY2thZ2VzKCJxcGNSIikKbGlicmFyeShxcGNSKQoKUFJFU1MoZnVsbE1MUi5maXQpClBSRVNTKHN0ZXBSLmZwLmZpdFtbMl1dJGNsbjIuMykKUFJFU1Moc3RlcFIuZnAuZml0W1szXV0kY2xuMi4zKQoKbGlicmFyeShnZ2ZvcnRpZnkpCmF1dG9wbG90KGZ1bGxNTFIuZml0JGNsbjIuMykKYXV0b3Bsb3Qoc3RlcFIuZnAuZml0W1sxXV0kY2xuMi4zKQoKZnVsbE1MUi5maXQkY2xuMi4zJG1vZGVsCgpwbG90KHN0ZXBSLmZwLmZpdFtbMl1dJGNsbjIuMykKY29va3MuZGlzdGFuY2UoZnVsbE1MUi5maXQkY2xuMi4zKSAlPiUgYnJvb206OnRpZHkoKSAlPiUgYXJyYW5nZShkZXNjKHgpKQoKbWxyLmRmICU+JSBmaWx0ZXIoZGVncm9uID09ICJjbG4yLjMiKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIAogIGZpbHRlcihyb3duYW1lID09ICI5MTYiKQoKbGFwcGx5KGZ1bGxNTFIuZml0LCBhdXRvcGxvdCkKCmxhcHBseShmdWxsTUxSLmZpdCwgZnVuY3Rpb24oYSl7CiAgY29va3MuZGlzdGFuY2UoYSkgJT4lIAogICAgYnJvb206OnRpZHkoKSAlPiUgCiAgICBhcnJhbmdlKGRlc2MoeCkpCn0pIAoKYGBgCgpgYGB7cn0KY29va3MuZGlzdGFuY2UoZnVsbE1MUi5maXQkY2xuMi4zKSAlPiUgYnJvb206OnRpZHkoKSAlPiUgYXJyYW5nZShkZXNjKHgpKQoKb3V0bGllcnMuY2xuMi4zIDwtIG1sci5kZiAlPiUgZmlsdGVyKGRlZ3JvbiA9PSAiY2xuMi4zIikgJT4lIAogIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSAKICBmaWx0ZXIocm93bmFtZSAlaW4lIGMoICIxNzgiLCI1NjQiLCI3NjEiLCI5MTYiKSkgJT4lIHB1bGwoY2VsbC5pZCkKYGBgCgpgYGB7cn0KbGFwcGx5KGZ1bGxNTFIuZml0LCBzdW1tYXJ5KQpgYGAKCgojZGYgdG8gYmUgdXNlZCB3aXRoIHN0ZXAgZnVuY3Rpb24KYGBge3J9CnRlbXAuZGYubGlzdCA8LSBtbHIuZGYyICU+JSAKICAgIGZpbHRlcih0cmVhdG1lbnQgPT0gIm5vbmUiKSAlPiUgIAogICMgbXV0YXRlKCBkbSA9IGxvZzEwKGRtKSkgJT4lIAogIHNwbGl0KC4kZGVncm9uKQpgYGAKCgojdXNpbmcgc3RlcEFJQyBmcm9tIE1BU1MKYGBge3J9CmxpYnJhcnkoTUFTUykKCmZ1bGwuc3RlcEFJQy5tYXNzIDwtIGxhcHBseSh0ZW1wLmRmLmxpc3QsIGZ1bmN0aW9uKGEpewogIG4gPC0gbnJvdyhhKQogIGxtLm9iaiA8LSBsbSh0LmhhbGYgfiAuLCBkYXRhID0gYSAlPiUgCiAgICAgZHBseXI6OnNlbGVjdChyZWdyZXNzb3JzLAogICAgICAgICAgICAgICAgICAgdC5oYWxmLAogICAgICAgICAgICAgICAgICAgLWR5LCAKICAgICAgICAgICAgICAgICAgIC10cmVhdG1lbnQpKQogICAgIAogc3RlcEFJQyhvYmplY3QgPSBsbS5vYmosIAogICAgIGRpcmVjdGlvbiA9ICJiYWNrd2FyZCIsIAogICAgIHRyYWNlID0gVCkKfSkKCmZ1bGwuc3RlcEFJQy5tYXNzICU+JSBtYXAoLixicm9vbTo6dGlkeSkKCmBgYAoKI3N0ZXAgQUlDIHdpdGggYWxsIHRoZSBmcCBtYXJrZXJzICsgY2VsbCBzaGFwZSAKYGBge3J9CmZ1bGwuc3RlcEFJQyA8LSBsYXBwbHkodGVtcC5kZi5saXN0LCBmdW5jdGlvbihhKXsKICBuIDwtIG5yb3coYSkKIHN0ZXAobG0odC5oYWxmIH4gLiwgZGF0YSA9IGEgJT4lIAogICAgIGRwbHlyOjpzZWxlY3QocmVncmVzc29ycywKICAgICAgICAgICAgICAgICAgIHQuaGFsZiwKICAgICAgICAgICAgICAgICAgIC1keSwgCiAgICAgICAgICAgICAgICAgICAtdHJlYXRtZW50KSksIAogICAgIGRpcmVjdGlvbiA9ICJiYWNrd2FyZCIsIAogICAgIHRyYWNlID0gVCwKICAgICAjIGsgPSBsb2cobiksCiAgICAgayA9MiApICNrID0gMiB3aGVuIHNtYWxsIGRhdGFzZXQgYW5kIGsgPSBsb2cobikgd2hlcmUgbiA9IG5vLiBvZiBvYnNlcnZhdGlvbnMgZm9yIHdoZW4gdGhlIGRhdGFzZXQgaXMgbGFyZ2UKfSkKCgpmdWxsLnN0ZXBBSUMgJT4lIAogIG1hcCguLCBicm9vbTo6Z2xhbmNlKSAlPiUgCiAgYmluZF9yb3dzKC5pZCA9ICJzYW1wbGUiKSAKICAjIGZpbHRlcihzYW1wbGUgJWluJSBjKCJtT0RDLjIiLCJjbG4yLjMiLCJjbG4yLjQiLCJzdGFibGUuMiIsInN0YWJsZS4zIikpCgpmdWxsLnN0ZXBBSUMgJT4lIAogIG1hcCguLCBicm9vbTo6dGlkeSkgCiAgIyBiaW5kX3Jvd3MoLmlkID0gInNhbXBsZSIpICU+JSAKICAjIGZpbHRlcihzYW1wbGUgJWluJSBjKCJtT0RDLjIiLCJjbG4yLjMiLCJjbG4yLjQiLCJzdGFibGUuMiIsInN0YWJsZS4zIiksIAogICAgICAgICAjIHAudmFsdWUgPCAwLjA1KSAlPiUgCgpmdWxsLnN0ZXBBSUMgJT4lIAogIG1hcCguLGZ1bmN0aW9uKGEpewogICAgYSRhbm92YSAKICB9KSAlPiUgCiAgYmluZF9yb3dzKC4sLmlkID0gImRlZ3JvbiIpICU+JSAKICBtdXRhdGUoU3RlcCA9IGFzLmNoYXJhY3RlcihTdGVwKSwgCiAgICAgICAgIFN0ZXAgPSBpZmVsc2UoU3RlcCA9PSAiIiwgIkZ1bGwiLFN0ZXApKSAlPiUgCiAgZ3JvdXBfYnkoZGVncm9uKSAlPiUgCiAgbXV0YXRlKGRlbC5haWMgPSBBSUNbMV0tQUlDKSAKCgpmdWxsLnN0ZXBBSUMuZnAgJT4lIAogIG1hcCguLGZ1bmN0aW9uKGEpewogICAgYSRhbm92YSAKICB9KSAlPiUgCiAgYmluZF9yb3dzKC4sLmlkID0gImRlZ3JvbiIpICU+JSAKICBtdXRhdGUoU3RlcCA9IGFzLmNoYXJhY3RlcihTdGVwKSwgCiAgICAgICAgIFN0ZXAgPSBpZmVsc2UoU3RlcCA9PSAiIiwgIkZ1bGwiLFN0ZXApKSAlPiUgCiAgZ3JvdXBfYnkoZGVncm9uKSAlPiUgCiAgbXV0YXRlKGRlbC5haWMgPSBBSUNbMV0tQUlDKSAKCmBgYAoKI1Bsb3QgdGhlIGFpYyBkaWZmZXJlbmNlIGF0IGVhY2ggc3RlcApgYGB7cn0KZnVsbC5zdGVwQUlDICU+JSAKICBtYXAoLixmdW5jdGlvbihhKXsKICAgIGEkYW5vdmEgCiAgfSkgJT4lIAogIGJpbmRfcm93cyguLC5pZCA9ICJkZWdyb24iKSAlPiUgCiAgbXV0YXRlKFN0ZXAgPSBhcy5jaGFyYWN0ZXIoU3RlcCksIAogICAgICAgICBTdGVwID0gaWZlbHNlKFN0ZXAgPT0gIiIsICJGdWxsIixTdGVwKSkgJT4lIAogIGdyb3VwX2J5KGRlZ3JvbikgJT4lIAogIG11dGF0ZShkZWwuYWljID0gQUlDWzFdLUFJQykgJT4lIAogIHNlbGVjdChkZWdyb24sIFN0ZXAsIGRlbC5haWMpICU+JSAKICBzcGxpdCguJGRlZ3JvbikgJT4lIAogIG1hcCguLGZ1bmN0aW9uKGEpewogICAgYVtucm93KGEpLF0gJT4lIAogICAgICBtdXRhdGUobW9kZWwgPSAicmVkdWNlZCIpCiAgfSkgJT4lIAogIGJpbmRfcm93cyguaWQgPSAiZGVncm9uIikgJT4lIAogIG11dGF0ZShkZWdyb24gPSBmYWN0b3IoZGVncm9uLCBsZXZlbHMgPSBjKCJHRlAtbU9EQyIsICJHRlAtQ0xOMiIsInllR0ZQIikpKSAlPiUgCiAgZ2dwbG90KC4sYWVzKHggPSBkZWwuYWljLCB5ID0gZGVncm9uKSkrCiAgZ2VvbV9jb2wod2lkdGggPSAwLjIpKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKSsKICAjIHNjYWxlX3hfbG9nMTAoKSsKICB4bGFiKFRlWCgiJERlbHRhKEFJQ197ZnVsbH0gLSBBSUNfe3N0ZXB9KSIpKSsKICB5bGFiKCJSZWdyZXNzb3IgRHJvcHBlZCIpKwogIHRoZW1lX3B1YnIoKSsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkKCmBgYAoKI3N0ZXAgQUlDIHdpdGggb25seSB0aGUgZmx1b3Jlc2NlbnQgbWFya2VycyAKYGBge3J9CmZ1bGwuc3RlcEFJQy5mcCA8LSBsYXBwbHkodGVtcC5kZi5saXN0LCBmdW5jdGlvbihhKXsKICBuIDwtIG5yb3coYSkKIHN0ZXAobG0odC5oYWxmIH4gLiwgZGF0YSA9IGEgJT4lIAogICAgIGRwbHlyOjpzZWxlY3QocmVncmVzc29ycy5mcCwKICAgICAgICAgICAgICAgICAgIHQuaGFsZiwKICAgICAgICAgICAgICAgICAgIC1keSwgCiAgICAgICAgICAgICAgICAgICAtdHJlYXRtZW50KSksIAogICAgIGRpcmVjdGlvbiA9ICJiYWNrd2FyZCIsIAogICAgIHRyYWNlID0gVCwKICAgICBrID0gMikKfSkKCiNsb29raW5nIGF0IHdoaWNoIHJlZ3Jlc3NvciBjb250cmlidXRlcyB0byB0aGUgb3ZlcmFsbCB2YXJpYWJpbGl0eSAKZnVsbC5zdGVwQUlDLmZwICU+JSAKICBtYXAoLiwgYnJvb206OnRpZHkpIAogICMgZmlsdGVyKHNhbXBsZSAlaW4lIGMoIm1PREMuMiIsImNsbjIuMyIsImNsbjIuNCIsInN0YWJsZS4yIiwic3RhYmxlLjMiKSkgJT4lIAogICMgc3BsaXQoLiRzYW1wbGUpCgojbW9kZWwgZml0IHN0YXRzCmZ1bGwuc3RlcEFJQy5mcCAlPiUgCiAgbWFwKC4sIGJyb29tOjpnbGFuY2UpICU+JSAKICBiaW5kX3Jvd3MoLmlkID0gInNhbXBsZSIpCgoKZnVsbC5zdGVwQUlDLmZwICU+JSAKICBtYXAoLixmdW5jdGlvbihhKXsKICAgIGEkYW5vdmEgCiAgfSkgJT4lIAogIGJpbmRfcm93cyguLC5pZCA9ICJkZWdyb24iKSAlPiUgCiAgbXV0YXRlKFN0ZXAgPSBhcy5jaGFyYWN0ZXIoU3RlcCksIAogICAgICAgICBTdGVwID0gaWZlbHNlKFN0ZXAgPT0gIiIsICJGdWxsIixTdGVwKSkgJT4lIAogIGdyb3VwX2J5KGRlZ3JvbikgJT4lIAogIG11dGF0ZShkZWwuYWljID0gQUlDLUFJQ1sxXSkgCmBgYAoKVmFyaWFuY2UgaW4gdC1oYWxmIGV4cGxhaW5lZCBieSBlYWNoIHJlZ3Jlc3Nvcgp1c2luZyBhbm92YQoKYGBge3J9CmZ1bGwuc3RlcEFJQy5mcCAlPiUgCiAgbWFwKC4sIGFub3ZhICU+JSBhcy5kYXRhLmZyYW1lKSAlPiUgCiAgYmluZF9yb3dzKC5pZCA9ICJzYW1wbGUiKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJwcmVkaWN0b3IiKSAlPiUgCiAgIyBmaWx0ZXIoc2FtcGxlICVpbiUgYygibU9EQy4yIiwiY2xuMi4zIiwiY2xuMi40Iiwic3RhYmxlLjIiLCJzdGFibGUuMyIpKSAlPiUgCiAgZ3JvdXBfYnkoc2FtcGxlKSAlPiUgCiAgbXV0YXRlKHZhci5leHAgPSAodmFsdWUuU3VtLlNxL3N1bSh2YWx1ZS5TdW0uU3EpKSoxMDApICU+JSAKICBzcGxpdCguJHNhbXBsZSkKCnZhci5leHBsYWluZWQgPC0gZnVsbC5zdGVwQUlDICU+JSAKICBtYXAoLiwgYW5vdmEgJT4lIGFzLmRhdGEuZnJhbWUpICU+JSAKICBiaW5kX3Jvd3MoLmlkID0gInNhbXBsZSIpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gInByZWRpY3RvciIpICU+JSAKICAjIGZpbHRlcihzYW1wbGUgJWluJSBjKCJtT0RDLjIiLCJjbG4yLjMiLCJjbG4yLjQiLCJzdGFibGUuMiIsInN0YWJsZS4zIikpICU+JSAKICBncm91cF9ieShzYW1wbGUpICU+JSAKICBtdXRhdGUodmFyLmV4cCA9ICh2YWx1ZS5TdW0uU3Evc3VtKHZhbHVlLlN1bS5TcSkpKjEwMCwgCiAgICAgICAgIHByZWRpY3RvciA9IHN0cl9zcGxpdChwcmVkaWN0b3IsIHBhdHRlcm4gPSAiXFwuXFwuXFwuIiwgc2ltcGxpZnkgPSBUKVssMV0sIAogICAgICAgICBwcmVkaWN0b3IgPSBjYXNlX3doZW4ocHJlZGljdG9yID09ICJnZnAubWVhbi5iZy5hZi5zdWIubmV3IiB+ICJHRlAiICwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZWRpY3RvciA9PSAiYXJlYSIgfiAiQXJlYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmVkaWN0b3IgPT0gInJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEiIH4gIlB1cDEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlZGljdG9yID09ICJkYXBpLnN1bS5iZy5zdWIucHVuY3RhIiB+ICJETkEiICwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZWRpY3RvciA9PSAic2hhcGUiIH4gIlNoYXBlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmVkaWN0b3IgPT0gImRtIiB+ICJSYXRlIG9mIE1hdHVyYXRpb24iCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRX5wcmVkaWN0b3IpKSAlPiUgCiAgc3BsaXQoLiRzYW1wbGUpCgp2YXIuZXhwbGFpbmVkCmBgYAoKI3Bsb3R0aW5nIHRoZSB2YXJpYW5jZSBleHBsYWluZWQgCmBgYHtyfQpyZW1haW4ucmVnIDwtIGRhdGEuZnJhbWUoc2FtcGxlID0gYygieWVHRlAtQ0xOMiIsInllR0ZQLUNMTjIiLCJ5ZUdGUCIsInllR0ZQIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgcHJlZGljdG9yID0gYygiUmF0ZSBvZiBNYXR1cmF0aW9uIiwgIlNoYXBlIiwiU2hhcGUiLCJQdXAxIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgdmFyLmV4cCA9IHJlcCgwLDQpLAogICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUuUHIuLkYuID0gcmVwKDAsNCkpCnZhci5leHAucGx0IDwtIHZhci5leHBsYWluZWQgJT4lIAogIGJpbmRfcm93cygpICU+JSAKICBiaW5kX3Jvd3MoLixyZW1haW4ucmVnKSAlPiUgCiAgZmlsdGVyKHByZWRpY3RvciAhPSAiUmVzaWR1YWxzIikgJT4lIAogIGRwbHlyOjpzZWxlY3Qoc2FtcGxlLCBwcmVkaWN0b3IsIHZhci5leHAsdmFsdWUuUHIuLkYuKSAlPiUgCiAgbXV0YXRlKHNhbXBsZSA9IGZhY3RvcihzYW1wbGUgLCBsZXZlbHMgPSBjKCJ5ZUdGUC1tT0RDIiwieWVHRlAtQ0xOMiIsInllR0ZQIikpKSAlPiUgCiAgIyBtdXRhdGUodmFyLnBhbCA9IGlmZWxzZSh2YWx1ZS5Qci4uRi4gPCAwLjA1LCAiPDAuMDUiLCI+MC4wNSIpKSAlPiUgCiAgYXJyYW5nZShzYW1wbGUpICU+JSAKICBnZ3Bsb3QoLixhZXMoeCA9IHByZWRpY3RvciwgeSA9IHZhci5leHAgKSkrCiAgZ2VvbV9jb2wod2lkdGggPSAwLjUpKwogIGZhY2V0X3dyYXAofnNhbXBsZSwgc2NhbGVzID0gImZyZWUiKSsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGZ1bmN0aW9uKHgpIHN0cl93cmFwKHgsIHdpZHRoID0gNSkpKwogIHRoZW1lX3B1YnIoKSsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuMSksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgeWxpbSgwLDIwKSsKICB5bGFiKCJWYXJpYW5jZSBleHBsYWluZWQgKCUpIikrCiAgeGxhYigiQ2VsbHVsYXIgZmVhdHVyZXMiKQp2YXIuZXhwLnBsdApgYGAKCiNzdGVwQUlDIHdpdGggcHJvdGVhc29tZSBpbmhpYml0aW9uIGV4cGVyaW1lbnRzCldpdGggYWxsIGZwIHJlZ3Jlc3NvcnMKYGBge3J9CnRlbXAuZGYubGlzdC5kbXNvIDwtIG1sci5kZiAlPiUgCiAgICBmaWx0ZXIodHJlYXRtZW50ICE9ICJub25lIikgJT4lICAKICBzcGxpdCguJHRyZWF0bWVudCkKCmZ1bGwuc3RlcEFJQy5mcC5kbXNvIDwtIGxhcHBseSh0ZW1wLmRmLmxpc3QuZG1zbywgZnVuY3Rpb24oYSl7CiBzdGVwKGxtKHQuaGFsZiB+IC4sIGRhdGEgPSBhICU+JSAKICAgICBkcGx5cjo6c2VsZWN0KHJlZ3Jlc3NvcnMuZnAsCiAgICAgICAgICAgICAgICAgICB0LmhhbGYsCiAgICAgICAgICAgICAgICAgICAtZHksIAogICAgICAgICAgICAgICAgICAgLXRyZWF0bWVudCkpLCAKICAgICBkaXJlY3Rpb24gPSAiYmFja3dhcmQiLCB0cmFjZSA9IFQpCn0pCgpsYXBwbHkoZnVsbC5zdGVwQUlDLmZwLmRtc28sIHN1bW1hcnkpICU+JSBtYXAoLiwgYnJvb206OnRpZHkpICU+JSAKICBiaW5kX3Jvd3MoLmlkID0gInNhbXBsZSIpICU+JSAKICBzcGxpdCguJHNhbXBsZSkKCmxhcHBseShmdWxsLnN0ZXBBSUMuZnAuZG1zbywgc3VtbWFyeSkgJT4lIG1hcCguLCBicm9vbTo6Z2xhbmNlKSAlPiUgCiAgYmluZF9yb3dzKC5pZCA9ICJzYW1wbGUiKSAlPiUgCiAgc3BsaXQoLiRzYW1wbGUpCmBgYAoKd2l0aCBmcCByZWdyZXNzb3JzICsgY2VsbHVhciBzaGFwZSAKYGBge3J9CnRlbXAuZGYubGlzdC5kbXNvIDwtIG1sci5kZiAlPiUgCiAgICBmaWx0ZXIodHJlYXRtZW50ICE9ICJub25lIikgJT4lICAKICBzcGxpdCguJHRyZWF0bWVudCkKCmZ1bGwuc3RlcEFJQy5kbXNvIDwtIGxhcHBseSh0ZW1wLmRmLmxpc3QuZG1zbywgZnVuY3Rpb24oYSl7CiBzdGVwKGxtKHQuaGFsZiB+IC4sIGRhdGEgPSBhICU+JSAKICAgICBkcGx5cjo6c2VsZWN0KHJlZ3Jlc3NvcnMuZnAsCiAgICAgICAgICAgICAgICAgICB0LmhhbGYsCiAgICAgICAgICAgICAgICAgICAtZHksIAogICAgICAgICAgICAgICAgICAgLXRyZWF0bWVudCkpLCAKICAgICBkaXJlY3Rpb24gPSAiYmFja3dhcmQiLCB0cmFjZSA9IFQpCn0pCgpsYXBwbHkoZnVsbC5zdGVwQUlDLmRtc28sIHN1bW1hcnkpICU+JSBtYXAoLiwgYnJvb206OnRpZHkpICU+JSAKICBiaW5kX3Jvd3MoLmlkID0gInNhbXBsZSIpICU+JSAKICBzcGxpdCguJHNhbXBsZSkKCmxhcHBseShmdWxsLnN0ZXBBSUMuZG1zbywgc3VtbWFyeSkgJT4lIG1hcCguLCBicm9vbTo6Z2xhbmNlKSAlPiUgCiAgYmluZF9yb3dzKC5pZCA9ICJzYW1wbGUiKSAlPiUgCiAgc3BsaXQoLiRzYW1wbGUpIAoKYGBgCgpWYXJpYW5jZSBpbiB0LWhhbGYgZXhwbGFpbmVkIGJ5IGVhY2ggcmVncmVzc29yCmBgYHtyfQpmdWxsLnN0ZXBBSUMuZG1zbyAlPiUgCiAgbWFwKC4sIGFub3ZhICU+JSBhcy5kYXRhLmZyYW1lKSAlPiUgCiAgYmluZF9yb3dzKC5pZCA9ICJzYW1wbGUiKSAlPiUgCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJwcmVkaWN0b3IiKSAlPiUgCiAgIyBmaWx0ZXIoc2FtcGxlICVpbiUgYygibU9EQy4yIiwiY2xuMi4zIiwiY2xuMi40Iiwic3RhYmxlLjIiLCJzdGFibGUuMyIpKSAlPiUgCiAgZ3JvdXBfYnkoc2FtcGxlKSAlPiUgCiAgbXV0YXRlKHZhci5leHAgPSAodmFsdWUuU3VtLlNxL3N1bSh2YWx1ZS5TdW0uU3EpKSoxMDApICU+JSAKICBzcGxpdCguJHNhbXBsZSkKCmZ1bGwuc3RlcEFJQy5mcC5kbXNvICU+JSAKICBtYXAoLiwgYW5vdmEgJT4lIGFzLmRhdGEuZnJhbWUpICU+JSAKICBiaW5kX3Jvd3MoLmlkID0gInNhbXBsZSIpICU+JSAKICByb3duYW1lc190b19jb2x1bW4odmFyID0gInByZWRpY3RvciIpICU+JSAKICAjIGZpbHRlcihzYW1wbGUgJWluJSBjKCJtT0RDLjIiLCJjbG4yLjMiLCJjbG4yLjQiLCJzdGFibGUuMiIsInN0YWJsZS4zIikpICU+JSAKICBncm91cF9ieShzYW1wbGUpICU+JSAKICBtdXRhdGUodmFyLmV4cCA9ICh2YWx1ZS5TdW0uU3Evc3VtKHZhbHVlLlN1bS5TcSkpKjEwMCkgJT4lIAogIHNwbGl0KC4kc2FtcGxlKQoKYGBgCgoKCiN1c2luZyByZWdzdWJzZXRzCmBgYHtyfQpsaWJyYXJ5KGxlYXBzKQpgYGAKCmBgYHtyfQpmdWxsLnJlZ1N1Yi5mcCA8LSBsYXBwbHkodGVtcC5kZi5saXN0LCBmdW5jdGlvbihhKXsKICBuIDwtIG5yb3coYSkKIHJlZ3N1YnNldHModC5oYWxmIH4gLiwgZGF0YSA9IGEgJT4lIAogICAgIGRwbHlyOjpzZWxlY3QocmVncmVzc29ycy5mcCwKICAgICAgICAgICAgICAgICAgIHQuaGFsZiwKICAgICAgICAgICAgICAgICAgIC1keSwgCiAgICAgICAgICAgICAgICAgICAtdHJlYXRtZW50KSwgCiAgICAgbnZtYXggPSBOVUxMKQp9KQoKcmVnU3ViLnN1bW1hcnkgPC0gZnVsbC5yZWdTdWIuZnAgJT4lIG1hcCguLHN1bW1hcnkpCgpsYXBwbHkocmVnU3ViLnN1bW1hcnksIGZ1bmN0aW9uKGEpewogIGRhdGEuZnJhbWUobW9kZWwgPSBhJG91dG1hdCwgCiAgICAgICAgICAgICBjcCA9IGEkY3AsCiAgICAgICAgICAgICBiaWMgPSBhJGJpYykKfSkgJT4lIGJpbmRfcm93cyguaWQgPSAiZGVncm9uIikgJT4lIAogIGdyb3VwX2J5KGRlZ3JvbikgJT4lIAogIGFycmFuZ2UoZGVncm9uLCBjcCkKYGBgCgpgYGB7cn0KZnVsbC5yZWdTdWIgPC0gbGFwcGx5KHRlbXAuZGYubGlzdCwgZnVuY3Rpb24oYSl7CiAgbiA8LSBucm93KGEpCiAgCiAgCiByZWdzdWJzZXRzKHQuaGFsZiB+IC4sIGRhdGEgPSBhICU+JSAKICAgICBkcGx5cjo6c2VsZWN0KHJlZ3Jlc3NvcnMsCiAgICAgICAgICAgICAgICAgICB0LmhhbGYsCiAgICAgICAgICAgICAgICAgICAtZHksIAogICAgICAgICAgICAgICAgICAgLXRyZWF0bWVudCksIAogICAgIG52bWF4ID0gTlVMTCkKfSkKCnJlZ1N1Yi5zdW1tYXJ5MiA8LSBmdWxsLnJlZ1N1YiAlPiUgbWFwKC4sc3VtbWFyeSkKCmxhcHBseShyZWdTdWIuc3VtbWFyeTIsIGZ1bmN0aW9uKGEpewogIGRhdGEuZnJhbWUobW9kZWwgPSBhJG91dG1hdCwgCiAgICAgICAgICAgICBjcCA9IGEkY3AsCiAgICAgICAgICAgICBiaWMgPSBhJGJpYykKfSkgJT4lIGJpbmRfcm93cyguaWQgPSAiZGVncm9uIikgJT4lIAogIGdyb3VwX2J5KGRlZ3JvbikgJT4lIAogIGFycmFuZ2UoZGVncm9uLCBiaWMKICAgICAgICAgICkgJT4lIHNwbGl0KC4kZGVncm9uKQpgYGAKCgoKI3Bsb3RzOiAKYGBge3J9CmdmcC42LmNvci5wbHQgPC0gbWxyLmRmICU+JQogIG11dGF0ZShkbSA9IGxvZzEwKGRtKSkgJT4lIAogIGZpbHRlcihkZWdyb24gJWluJSBjKCJtT0RDLjIiLCAiY2xuMi4zIiwgImNsbjIuNCIsICJzdGFibGUuMiIsICJzdGFibGUuMyIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KHQuaGFsZiwKICAgICAgICAgcmVncmVzc29ycywKICAgICAgICAgZGVncm9uKSAlPiUKICByZW5hbWUoCiAgICAiR0ZQIiA9ICJnZnAubWVhbi5iZy5hZi5zdWIubmV3IiwKICAgICJQdXAxLXREaW1lciIgPSAicmZwLm1lYW4uYmcuc3ViLnB1bmN0YSIsCiAgICAiRE5BIiA9ICJkYXBpLnN1bS5iZy5zdWIucHVuY3RhIiwKICAgICJBcmVhIiA9ICJhcmVhIgogICkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAyOjcpICU+JQogIG11dGF0ZShkZWdyb24gPSBjYXNlX3doZW4oCiAgICAgIGRlZ3JvbiAlaW4lIGMoImNsbjIuMyIsICJjbG4yLjIiLCAiY2xuMiIsICJjbG4yLjQiKSB+ICJ5ZUdGUC1DTE4yIiwKICAgICAgZGVncm9uICVpbiUgYygibU9EQy4yIiwgIm1PREMiKSAgfiAieWVHRlAtbU9EQyIsCiAgICAgIGRlZ3JvbiAlaW4lIGMoInN0YWJsZSIsICJzdGFibGUuMiIsICJzdGFibGUuMyIpIH4gInllR0ZQIgogICAgKSwKICAgIGRlZ3JvbiA9IGZhY3RvcihkZWdyb24gLCBsZXZlbHMgPSBjKCJ5ZUdGUC1tT0RDIiwgInllR0ZQLUNMTjIiLCAieWVHRlAiKSkKICApICU+JQogIGZpbHRlcighKG5hbWUgJWluJSBjKCJzaGFwZSIsImRtIikpKSAlPiUgCiAgZ2dwbG90KC4sIGFlcyh4ID0gdmFsdWUsIHkgPSB0LmhhbGYpKSArCiAgICAgIGdncG9pbnRkZW5zaXR5OjpnZW9tX3BvaW50ZGVuc2l0eShzaXplID0gMC4yLCBndWlkZXMgPSBGKSArCiAgICAgIHN0YXRfY29yKHNpemUgPSAyKSArCiAgICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZDQiLCBzaXplID0gMC41KSsKICAgICAgZmFjZXRfd3JhcChkZWdyb24gfiBuYW1lLCBzY2FsZXMgPSAiZnJlZSIsIG5jb2wgPSA0KSArCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICBsYWJzKHggPSBOVUxMKSArCiAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwKSwKICAgICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgyLCJtbSIpLCAKICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAKICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjEpKSsKICB5bGFiKCJIYWxmLWxpZmUgW21pbi5dIikrCiAgeGxhYigiQS5VIikKICAKZ2ZwLjYuY29yLnBsdApgYGAKCmBgYHtyfQpnZnAuMy5jb3IucGx0IDwtIG1sci5kZiAlPiUKICBmaWx0ZXIoZGVncm9uICVpbiUgYygibU9EQy4yIiwgImNsbjIuMyIsICJjbG4yLjQiLCAic3RhYmxlLjIiLCAic3RhYmxlLjMiKSkgJT4lCiAgZHBseXI6OnNlbGVjdCh0LmhhbGYsCiAgICAgICAgIHJlZ3Jlc3NvcnMuZnAsCiAgICAgICAgIGRlZ3JvbikgJT4lCiAgcmVuYW1lKAogICAgIkdGUCBpbnRlbnNpdHkiID0gImdmcC5tZWFuLmJnLmFmLnN1Yi5uZXciLAogICAgIlB1cDEtdERpbWVyIiA9ICJyZnAubWVhbi5iZy5zdWIucHVuY3RhIiwKICAgICJUb3RhbCBETkEgSW50LiIgPSAiZGFwaS5zdW0uYmcuc3ViLnB1bmN0YSIKICApICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gMjo0KSAlPiUKICBtdXRhdGUoCiAgICBkZWdyb24gPSBjYXNlX3doZW4oCiAgICAgIGRlZ3JvbiAlaW4lIGMoImNsbjIuMyIsICJjbG4yLjQiKSB+ICJ5ZUdGUC1DTE4yIiwKICAgICAgZGVncm9uICVpbiUgYygibU9EQy4yIikgIH4gInllR0ZQLW1PREMiLAogICAgICBkZWdyb24gJWluJSBjKCJzdGFibGUuMiIsICJzdGFibGUuMyIpIH4gInllR0ZQIgogICAgKSwKICAgIGRlZ3JvbiA9IGZhY3RvcihkZWdyb24gLCBsZXZlbHMgPSBjKCJ5ZUdGUC1tT0RDIiwgInllR0ZQLUNMTjIiLCAieWVHRlAiKSkKICApICU+JQogIGdncGxvdCguLCBhZXMoeCA9IHZhbHVlLCB5ID0gdC5oYWxmKSkgKwogIGdncG9pbnRkZW5zaXR5OjpnZW9tX3BvaW50ZGVuc2l0eShzaXplID0gMC4yLCBndWlkZXMgPSBGKSArCiAgc3RhdF9jb3Ioc2l6ZSA9IDIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJyZWQ0Iiwgc2l6ZSA9IDAuNSkrCiAgICAgIGZhY2V0X3dyYXAoZGVncm9uIH4gbmFtZSwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICBsYWJzKHggPSBOVUxMKSArCiAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwKSwKICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKSsKICB5bGFiKCJIYWxmLUxpZmUgW21pbi5dIikrCiAgeGxhYigiSW50ZW5zaXR5IFtBLlUuXSIpCgpnZnAuMy5jb3IucGx0CmBgYApHRlAgaW50ZW5zaXR5IHZzIHQtaGFsZiBjb3IgcGxvdCAKYGBge3J9CmdmcC5JbnQuY29yLnBsdCA8LSBtbHIuZGYgJT4lCiAgZmlsdGVyKGRlZ3JvbiAlaW4lIGMoIm1PREMuMiIsICJjbG4yLjMiLCAiY2xuMi40IiwgInN0YWJsZS4yIiwgInN0YWJsZS4zIikpICU+JQogIGRwbHlyOjpzZWxlY3QodC5oYWxmLAogICAgICAgICBnZnAubWVhbi5iZy5hZi5zdWIubmV3LAogICAgICAgICBkZWdyb24pICU+JQogIG11dGF0ZSgKICAgIGRlZ3JvbiA9IGNhc2Vfd2hlbigKICAgICAgZGVncm9uICVpbiUgYygiY2xuMi4zIiwgImNsbjIuNCIpIH4gInllR0ZQLUNMTjIiLAogICAgICBkZWdyb24gJWluJSBjKCJtT0RDLjIiKSAgfiAieWVHRlAtbU9EQyIsCiAgICAgIGRlZ3JvbiAlaW4lIGMoInN0YWJsZS4yIiwgInN0YWJsZS4zIikgfiAieWVHRlAiCiAgICApLAogICAgZGVncm9uID0gZmFjdG9yKGRlZ3JvbiAsIGxldmVscyA9IGMoInllR0ZQLW1PREMiLCAieWVHRlAtQ0xOMiIsICJ5ZUdGUCIpKQogICkgJT4lCiAgZ2dwbG90KC4sIGFlcyh4ID0gZ2ZwLm1lYW4uYmcuYWYuc3ViLm5ldywgeSA9IHQuaGFsZikpICsKICBnZ3BvaW50ZGVuc2l0eTo6Z2VvbV9wb2ludGRlbnNpdHkoc2l6ZSA9IDAuMiwgZ3VpZGVzID0gRikgKwogIHN0YXRfY29yKHNpemUgPSA2KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAicmVkNCIsIHNpemUgPSAwLjUpKwogICAgICBmYWNldF93cmFwKH5kZWdyb24gLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICAgdGhlbWVfYncoKSArCiAgICAgIGxhYnMoeCA9IE5VTEwpICsKICAgICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwKSwKICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKSsKICB5bGFiKCJIYWxmLUxpZmUgW21pbi5dIikrCiAgeGxhYigiR0ZQIEludGVuc2l0eSBbQS5VLl0iKQoKZ2ZwLkludC5jb3IucGx0CmBgYAoKI3BhdGNod29yayBmb3IgMyBjZWxsdWxhciBmZWF0dXJlcyBhbmQgdC1oYWxmCmBgYHtyIGZpZy5oZWlnaHQ9IDQsIGZpZy53aWR0aD0gNSB9CmNlbGx1bGFyLmhhbGZMaWZlLnBsdCA8LSAoZGVsdGFSMi5wbHQuYWxsL2dmcC4zLmNvci5wbHQpKwogIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICJjb2xsZWN0IiwgaGVpZ2h0cyA9IGMoMC4zLDAuNykpKwogIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gIkEiKQoKY2VsbHVsYXIuaGFsZkxpZmUucGx0CmBgYAoKYGBge3J9Cmdnc2F2ZShwbG90ID0gY2VsbHVsYXIuaGFsZkxpZmUucGx0LCBmaWxlbmFtZSA9ICJjZWxsdWxhcl9oYWxmTGlmZV9jb3IucG5nIiwgcGF0aCA9ICJ+L3Bsb3RzL3BhcGVyMS9maWd1cmVzL2ZpZ18yLyIsIHdpZHRoID0gNi41LCBoZWlnaHQgPSA4KQpnZ3NhdmUocGxvdCA9IGNlbGx1bGFyLmhhbGZMaWZlLnBsdCwgZmlsZW5hbWUgPSAiY2VsbHVsYXJfaGFsZkxpZmVfY29yLnBkZiIsIHBhdGggPSAifi9wbG90cy9wYXBlcjEvZmlndXJlcy9maWdfMi8iLCB3aWR0aCA9IDYuNSwgaGVpZ2h0ID0gOCkKYGBgCgojcGF0Y2h3b3JrIGZvciBHRlAgaW50ZW5zaXR5IGFuZCB0LWhhbGYgCmBgYHtyICB9CmdmcEludC5oYWxmTGlmZS5wbHQgPC0gKGRlbHRhUjIucGx0LmFsbC9nZnAuSW50LmNvci5wbHQpKwogIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICJjb2xsZWN0IikrCiAgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpCgpnZnBJbnQuaGFsZkxpZmUucGx0CmBgYApgYGB7cn0KZ2dzYXZlKHBsb3QgPSBnZnBJbnQuaGFsZkxpZmUucGx0LCBmaWxlbmFtZSA9ICJnZnBJbnRfaGFsZkxpZmVfY29yLnBuZyIsIHBhdGggPSAifi9wbG90cy9wYXBlcjEvZmlndXJlcy9maWdfMi8iLCB3aWR0aCA9IDUuNSwgaGVpZ2h0ID0gNikKZ2dzYXZlKHBsb3QgPSBnZnBJbnQuaGFsZkxpZmUucGx0LCBmaWxlbmFtZSA9ICJnZnBJbnRfaGFsZkxpZmVfY29yLnBkZiIsIHBhdGggPSAifi9wbG90cy9wYXBlcjEvZmlndXJlcy9maWdfMi8iLCB3aWR0aCA9IDUuNSwgaGVpZ2h0ID0gNikKYGBgCgoKCiNmb3IgR1JDIHBvc3RlcgpgYGB7cn0KZ2dzYXZlKHBsb3QgPSB2YXIuZXhwLnBsdCwgZmlsZW5hbWUgPSAidmFyX2V4cGxhaW5lZC5wZGYiLHBhdGggPSAifi9wbG90cy9wYXBlcjEvZmlndXJlcy9maWdfMi8iLCB3aWR0aCA9MTIsIGhlaWdodCA9IDMpCmdnc2F2ZShwbG90ID1nZnAuSW50LmNvci5wbHQgLCBmaWxlbmFtZSA9ICJnZnBJbnRfY29yLnBkZiIscGF0aCA9ICJ+L3Bsb3RzL3BhcGVyMS9maWd1cmVzL2ZpZ18yLyIsIHdpZHRoID0xMiwgaGVpZ2h0ID0gMykKYGBgCgp3aXRoIHByb3R0ZWluIGluaGliaXRpb24KYGBge3J9CiBtbHIuZGYgJT4lCiAgbXV0YXRlKGRtID0gbG9nMTAoZG0pKSAlPiUgCiAgZmlsdGVyKGRlZ3JvbiAlaW4lIGMgKCJtT0RDIikgKSAlPiUKICAjIGZpbHRlcighKHRyZWF0bWVudCAlaW4lIGMoIm5vbmUiLCAiZG1zbzEiLCI1MHVNIikpLCAKICAgICAgICAgIyBpZmVsc2UodHJlYXRtZW50ID09ICI1dU0iLCB0LmhhbGYgPCAxMzguNjI5NCwgdC5oYWxmID09IHQuaGFsZikpICU+JSAgCiAgZHBseXI6OnNlbGVjdCh0LmhhbGYsCiAgICAgICAgIHJlZ3Jlc3NvcnMsCiAgICAgICAgIGRlZ3JvbiwKICAgICAgICAgdHJlYXRtZW50KSAlPiUKICByZW5hbWUoCiAgICAiR0ZQIiA9ICJnZnAubWVhbi5iZy5hZi5zdWIubmV3IiwKICAgICJQdXAxLXREaW1lciIgPSAicmZwLm1lYW4uYmcuc3ViLnB1bmN0YSIsCiAgICAiRE5BIiA9ICJkYXBpLnN1bS5iZy5zdWIucHVuY3RhIiwKICAgICJBcmVhIiA9ICJhcmVhIgogICkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAyOjcpICU+JQogIG11dGF0ZShkZWdyb24gPSBjYXNlX3doZW4oCiAgICBkZWdyb24gJWluJSBjKCJtT0RDIikgIH4gInllR0ZQLW1PREMiKSwKICAgIHRyZWF0bWVudCA9IGZhY3Rvcih0cmVhdG1lbnQsIGxldmVscyA9IGMoIm5vbmUiLCJkbXNvMSIsImRtc28yIiwiMXVNIiwiMi41dU0iLCI1dU0iLCI1MHVNIikpKSAlPiUKICBmaWx0ZXIoIShuYW1lICVpbiUgYygic2hhcGUiLCJkbSIpKSkgJT4lIAogIGdncGxvdCguLCBhZXMoeCA9IHZhbHVlLCB5ID0gdC5oYWxmKSkgKwogICAgICBnZ3BvaW50ZGVuc2l0eTo6Z2VvbV9wb2ludGRlbnNpdHkoc2l6ZSA9IDAuMiwgZ3VpZGVzID0gRikgKwogICAgICBzdGF0X2NvcihzaXplID0gMikgKwogICAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJyZWQ0Iiwgc2l6ZSA9IDAuNSkrCiAgICAgIGZhY2V0X2dyaWQodHJlYXRtZW50IH4gbmFtZSwgc2NhbGVzID0gImZyZWUiKSArCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICBsYWJzKHggPSBOVUxMKSArCiAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwKSwKICAgICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgyLCJtbSIpLCAKICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsKICB5bGFiKCJIYWxmLUxpZmUgW21pbi5dIikrCiAgeGxhYigiQS5VIikKCmBgYAoKYGBge3J9Cm1sci5kZiAlPiUKICBtdXRhdGUoZG0gPSBsb2cxMChkbSkpICU+JSAKICBmaWx0ZXIoZGVncm9uICVpbiUgYyAoIm1PREMiKSApICU+JQogIGZpbHRlcighKHRyZWF0bWVudCAlaW4lIGMoIm5vbmUiLCAiZG1zbzEiLCI1MHVNIikpLCAKICAgICAgICAgaWZlbHNlKHRyZWF0bWVudCA9PSAiNXVNIiwgdC5oYWxmIDwgMTM4LjYyOTQsIHQuaGFsZiA9PSB0LmhhbGYpKSAlPiUgCiAgZHBseXI6OnNlbGVjdCh0LmhhbGYsCiAgICAgICAgIHJlZ3Jlc3NvcnMsCiAgICAgICAgIGRlZ3JvbiwKICAgICAgICAgdHJlYXRtZW50KSAlPiUgCiAgZ2dwbG90KC4sYWVzKHggPSBhcmVhLCB5ID0gcmZwLm1lYW4uYmcuc3ViLnB1bmN0YSkpKwogIGdlb21fcG9pbnQoKSsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEYpKwogIGZhY2V0X3dyYXAofnRyZWF0bWVudCkrCiAgc3RhdF9jb3IoKQpgYGAKCgpgYGB7cn0KbWxyLmRmICU+JSAKICBmaWx0ZXIodHJlYXRtZW50ID09ICJub25lIikgJT4lIAogIGdncGxvdCguLGFlcyh4ID0gZGFwaS5zdW0uYmcuc3ViLnB1bmN0YSkpKwogIGdlb21faGlzdG9ncmFtKCkrCiAgZmFjZXRfd3JhcCh+ZGVncm9uLCBzY2FsZXMgPSAiZnJlZSIpCmBgYAojZ2dwYWlycyAKCmBgYHtyfQojdG8gYmUgdXNlZCB3aXRoIGdncGFpcnMKbXlfZm4gPC0gZnVuY3Rpb24oZGF0YSwgbWFwcGluZywgLi4uKXsKICBwIDwtIGdncGxvdChkYXRhID0gZGF0YSwgbWFwcGluZyA9IG1hcHBpbmcpICsgCiAgICBnZ3BvaW50ZGVuc2l0eTo6Z2VvbV9wb2ludGRlbnNpdHkoc2l6ZSA9IDAuMSkrCiAgICAjIGdlb21fcG9pbnQoc2l6ZSA9IDAuMSwgYWxwaGEgPSAwLjEpICsgCiAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIiwgIGNvbG9yPSJyZWQ0Iiwgc2UgPSBGQUxTRSwgbHdkID0gMC41KSsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICBwCn0KCmdmcC5hcmVhLmNvci5nZ1BhaXIgPC0gbWxyLmRmICU+JQogIGZpbHRlcihkZWdyb24gJWluJSBjKCJtT0RDLjIiLCAiY2xuMi4zIiwgImNsbjIuNCIsICJzdGFibGUuMiIsICJzdGFibGUuMyIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KHQuaGFsZiwKICAgICAgICAgcmVncmVzc29ycywKICAgICAgICAgZGVncm9uKSAlPiUKICByZW5hbWUoCiAgICAiR0ZQIiA9ICJnZnAubWVhbi5iZy5hZi5zdWIubmV3IiwKICAgICJQdXAxLXREaW1lciIgPSAicmZwLm1lYW4uYmcuc3ViLnB1bmN0YSIsCiAgICAiRE5BIiA9ICJkYXBpLnN1bS5iZy5zdWIucHVuY3RhIiwKICAgICJBcmVhIiA9ICJhcmVhIgogICkgJT4lCiAgZHBseXI6OnNlbGVjdChBcmVhLCBETkEsIGBQdXAxLXREaW1lcmAsR0ZQLGRlZ3JvbiApICU+JSAKICBtdXRhdGUoCiAgICBkZWdyb24gPSBjYXNlX3doZW4oCiAgICAgIGRlZ3JvbiAlaW4lIGMoImNsbjIuMyIsICJjbG4yLjQiKSB+ICJ5ZUdGUC1DTE4yIiwKICAgICAgZGVncm9uICVpbiUgYygibU9EQy4yIikgIH4gInllR0ZQLW1PREMiLAogICAgICBkZWdyb24gJWluJSBjKCJzdGFibGUuMiIsICJzdGFibGUuMyIpIH4gInllR0ZQIgogICAgKSwKICAgIGRlZ3JvbiA9IGZhY3RvcihkZWdyb24gLCBsZXZlbHMgPSBjKCJ5ZUdGUC1tT0RDIiwgInllR0ZQLUNMTjIiLCAieWVHRlAiKSkKICApICU+JQogIHNwbGl0KC4kZGVncm9uKSAlPiUgCiAgbWFwKC4sZnVuY3Rpb24oYSl7CiAgICBhICU+JSAKICAgICAgZ2dwYWlycyguLAogICAgICAgICAgIyBsZWdlbmQgPSA1LAogICAgICAgICAgY29sdW1ucyA9IDE6NCwKICAgICAgICAgICMgbWFwcGluZyA9IGdncGxvdDI6OmFlcyhjb2xvciA9IFJlcGxpY2F0ZSksCiAgICAgICAgICBsb3dlciA9IGxpc3QoY29udGludW91cyA9IG15X2ZuLAogICAgICAgICAgICAgICAgICAgICAgZGlzY3JldGUgPSAiYmxhbmsiLCAKICAgICAgICAgICAgICAgICAgICAgIGNvbWJvPSJibGFuayIpLCAKICAgICAgICAgICMgdXBwZXIgPSAiYmxhbmsiLAogICAgICAgICAgIyBkaWFnID0gTlVMTCwKICAgICAgICAgICBkaWFnID0gbGlzdChkaXNjcmV0ZT0iYmFyRGlhZyIsCiAgICAgICAgICAgICAgICAgICAgICBjb250aW51b3VzID0gd3JhcCgiZGVuc2l0eURpYWciLCBhbHBoYT0wLjUgKSksCiAgICAgICAgICB1cHBlciA9IGxpc3QoZGlzY3JldGU9IHdyYXAoImJhckRpYWciICwgb3V0bGllci5zaXplID0gMC41KSwKICAgICAgICAgICAgICAgICAgICAgICBjb21ibyA9IHdyYXAoImJveF9ub19mYWNldCIsIG91dGxpZXIuc2l6ZSA9IDAuNSksCiAgICAgICAgICAgICAgICAgICAgICAgY29udGludW91cyA9IHdyYXAoImNvciIsIGRpc3BsYXlfZ3JpZCA9IEZBTFNFLCBzaXplID0gMi41ICwgbWV0aG9kID0gInBlYXJzb24iLCBjb2xvciA9ICJyZWQ0IikpLAogICAgICAgICAgbGFiZWxsZXIgPSBsYWJlbF93cmFwX2dlbih3aWR0aCA9IDIsIG11bHRpX2xpbmUgPSBUUlVFKSkrCiAgdGhlbWVfYncoKSsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCBoanVzdCA9IDEpKSsKICAgICAgbGFicyh0aXRsZSA9IGEkZGVncm9uWzFdKQogIH0pCiAgCmdmcC5hcmVhLmNvci5nZ1BhaXIKYGBgCmBgYHtyfQpnZ3NhdmUocGxvdCA9IGdmcC5hcmVhLmNvci5nZ1BhaXIkYHllR0ZQLW1PRENgLCBmaWxlbmFtZSA9ICJnZnBfbU9EQ180Q29yX2dnUC5wbmciLCBwYXRoID0gIn4vcGxvdHMvcGFwZXIxL2ZpZ3VyZXMvZmlnXzIvIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAzLjUpCgpnZ3NhdmUocGxvdCA9IGdmcC5hcmVhLmNvci5nZ1BhaXIkYHllR0ZQLW1PRENgLCBmaWxlbmFtZSA9ICJnZnBfbU9EQ180Q29yX2dnUC5wZGYiLCBwYXRoID0gIn4vcGxvdHMvcGFwZXIxL2ZpZ3VyZXMvZmlnXzIvIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAzLjUpCgpnZ3NhdmUocGxvdCA9IGdmcC5hcmVhLmNvci5nZ1BhaXIkYHllR0ZQLUNMTjJgLCBmaWxlbmFtZSA9ICJnZnBfY2xuMl80Q29yX2dnUC5wbmciLCBwYXRoID0gIn4vcGxvdHMvcGFwZXIxL2ZpZ3VyZXMvZmlnXzIvIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAzLjUpCgpnZ3NhdmUocGxvdCA9IGdmcC5hcmVhLmNvci5nZ1BhaXIkYHllR0ZQLUNMTjJgLCBmaWxlbmFtZSA9ICJnZnBfY2xuMl80Q29yX2dnUC5wZGYiLCBwYXRoID0gIn4vcGxvdHMvcGFwZXIxL2ZpZ3VyZXMvZmlnXzIvIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAzLjUpCgpnZ3NhdmUocGxvdCA9IGdmcC5hcmVhLmNvci5nZ1BhaXIkYHllR0ZQYCwgZmlsZW5hbWUgPSAiZ2ZwXzRDb3JfZ2dQLnBuZyIsIHBhdGggPSAifi9wbG90cy9wYXBlcjEvZmlndXJlcy9maWdfMi8iLCB3aWR0aCA9IDQsIGhlaWdodCA9IDMuNSkKCmdnc2F2ZShwbG90ID0gZ2ZwLmFyZWEuY29yLmdnUGFpciRgeWVHRlBgLCBmaWxlbmFtZSA9ICJnZnBfNENvcl9nZ1AucGRmIiwgcGF0aCA9ICJ+L3Bsb3RzL3BhcGVyMS9maWd1cmVzL2ZpZ18yLyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMy41KQpgYGAKCmBgYHtyfQp0ZXN0LmdnUCA8LSAod3JhcF9lbGVtZW50cyhnZ21hdHJpeF9ndGFibGUoZ2ZwLmFyZWEuY29yLmdnUGFpciRgeWVHRlAtbU9EQ2ApKXx3cmFwX2VsZW1lbnRzKGdnbWF0cml4X2d0YWJsZShnZnAuYXJlYS5jb3IuZ2dQYWlyJGB5ZUdGUC1DTE4yYCkpfCB3cmFwX2VsZW1lbnRzKGdnbWF0cml4X2d0YWJsZShnZnAuYXJlYS5jb3IuZ2dQYWlyJHllR0ZQKSkpKwogcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpCmBgYAoKYGBge3J9Cmdnc2F2ZShwbG90ID0gdGVzdC5nZ1AsIGZpbGVuYW1lID0gInRlc3RfZ2dQLnBkZiIsIHBhdGggPSAifi9wbG90cy9wYXBlcjEvZmlndXJlcy9maWdfMi8iLCB3aWR0aCA9IDYuNSwgaGVpZ2h0ID0gMykKYGBgCgojYXJlYSB2cyBwdXAxIHZzIGRuYSB2cyBnZnAKYGBge3J9CmRmX2NvclN1cF9maWcgPC0gbWxyLmRmICU+JQogIGZpbHRlcihkZWdyb24gJWluJSBjKCJtT0RDLjIiLCAiY2xuMi4zIiwgImNsbjIuNCIsICJzdGFibGUuMiIsICJzdGFibGUuMyIpKSAlPiUKICBkcGx5cjo6c2VsZWN0KHQuaGFsZiwKICAgICAgICAgcmVncmVzc29ycywKICAgICAgICAgZGVncm9uKSAlPiUKICByZW5hbWUoCiAgICAiR0ZQIiA9ICJnZnAubWVhbi5iZy5hZi5zdWIubmV3IiwKICAgICJQdXAxLXREaW1lciIgPSAicmZwLm1lYW4uYmcuc3ViLnB1bmN0YSIsCiAgICAiRE5BIiA9ICJkYXBpLnN1bS5iZy5zdWIucHVuY3RhIiwKICAgICJBcmVhIiA9ICJhcmVhIgogICkgJT4lCiAgZHBseXI6OnNlbGVjdChBcmVhLCBETkEsIGBQdXAxLXREaW1lcmAsR0ZQLGRlZ3JvbiApICU+JSAKICBtdXRhdGUoCiAgICBkZWdyb24gPSBjYXNlX3doZW4oCiAgICAgIGRlZ3JvbiAlaW4lIGMoImNsbjIuMyIsICJjbG4yLjQiKSB+ICJ5ZUdGUC1DTE4yIiwKICAgICAgZGVncm9uICVpbiUgYygibU9EQy4yIikgIH4gInllR0ZQLW1PREMiLAogICAgICBkZWdyb24gJWluJSBjKCJzdGFibGUuMiIsICJzdGFibGUuMyIpIH4gInllR0ZQIgogICAgKSwKICAgIGRlZ3JvbiA9IGZhY3RvcihkZWdyb24gLCBsZXZlbHMgPSBjKCJ5ZUdGUC1tT0RDIiwgInllR0ZQLUNMTjIiLCAieWVHRlAiKSkKICApIApgYGAKCmBgYHtyfQoKYXJlYS5wdXAxIDwtIGRmX2NvclN1cF9maWcgJT4lIAogIGZpbHRlcihkZWdyb24gPT0gInllR0ZQLW1PREMiKSAlPiUgCiAgZ2dwbG90KC4sYWVzKHggPSBBcmVhLCB5ID0gYFB1cDEtdERpbWVyYCkpKwogIGdncG9pbnRkZW5zaXR5OjpnZW9tX3BvaW50ZGVuc2l0eShzaXplID0gMC4yLCBndWlkZXMgPSBGKSArCiAgICAgIHN0YXRfY29yKHNpemUgPSAzKSArCiAgICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZDQiLCBzaXplID0gMC41KSsKICAgICAgdGhlbWVfYncoKSArCiAgICAgIGxhYnMoeCA9IE5VTEwpICsKICAgICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzApLAogICAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDIsIm1tIiksIAogICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuMSkpKwogIHlsYWIoIlB1cDEtdERpbWVyIFtBLlVdIikrCiAgeGxhYigiQXJlYSBbQS5VXSIpCgpkbmEucHVwMSA8LSBkZl9jb3JTdXBfZmlnICU+JSAKICBmaWx0ZXIoZGVncm9uID09ICJ5ZUdGUC1tT0RDIikgJT4lIAogIGdncGxvdCguLGFlcyh4ID0gRE5BLCB5ID0gYFB1cDEtdERpbWVyYCkpKwogIGdncG9pbnRkZW5zaXR5OjpnZW9tX3BvaW50ZGVuc2l0eShzaXplID0gMC4yLCBndWlkZXMgPSBGKSArCiAgICAgIHN0YXRfY29yKHNpemUgPSAzKSArCiAgICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZDQiLCBzaXplID0gMC41KSsKICAgICAgdGhlbWVfYncoKSArCiAgICAgIGxhYnMoeCA9IE5VTEwpICsKICAgICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzApLAogICAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDIsIm1tIiksIAogICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuMSkpKwogIHlsYWIoIlB1cDEtdERpbWVyIFtBLlVdIikrCiAgeGxhYigiRE5BIFtBLlVdIikKCmRuYS5hcmVhIDwtIGRmX2NvclN1cF9maWcgJT4lCiAgZmlsdGVyKGRlZ3JvbiA9PSAieWVHRlAtbU9EQyIpICU+JSAKICBnZ3Bsb3QoLixhZXMoeCA9IEROQSwgeSA9IEFyZWEpKSsKICBnZ3BvaW50ZGVuc2l0eTo6Z2VvbV9wb2ludGRlbnNpdHkoc2l6ZSA9IDAuMiwgZ3VpZGVzID0gRikgKwogICAgICBzdGF0X2NvcihzaXplID0gMykgKwogICAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJyZWQ0Iiwgc2l6ZSA9IDAuNSkrCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICBsYWJzKHggPSBOVUxMKSArCiAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwKSwKICAgICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgyLCJtbSIpLCAKICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAKICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjEpKSsKICB5bGFiKCJBcmVhIFtBLlVdIikrCiAgeGxhYigiRE5BIFtBLlVdIikKYGBgCgpgYGB7cn0KZ2ZwSW50LmNvci5wbHQgPC0gZGZfY29yU3VwX2ZpZyAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAxOjMpICU+JSAKICAjIGZpbHRlcihkZWdyb24gPT0gInllR0ZQLW1PREMiKSAlPiUgCiAgZ2dwbG90KC4sYWVzKHggPSB2YWx1ZSwgeSA9IEdGUCkpKwogIGdncG9pbnRkZW5zaXR5OjpnZW9tX3BvaW50ZGVuc2l0eShzaXplID0gMC4yLCBndWlkZXMgPSBGKSArCiAgICAgIHN0YXRfY29yKHNpemUgPSAzKSArCiAgICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZDQiLCBzaXplID0gMC41KSsKICBmYWNldF93cmFwKGRlZ3Jvbn5uYW1lLCBzY2FsZXMgPSAiZnJlZSIpKwogICAgICB0aGVtZV9idygpICsKICAgICAgbGFicyh4ID0gTlVMTCkgKwogICAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCksCiAgICAgICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMiwibW0iKSwgCiAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgCiAgICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShzaXplID0gMC4xKSkrCiAgeGxhYigiQS5VIikKYGBgCgpgYGB7cn0KdGVzdF9jb3IgPC0gKChhcmVhLnB1cDF8ZG5hLnB1cDF8ZG5hLmFyZWEpL2dmcEludC5jb3IucGx0KSsKICBwbG90X2xheW91dChoZWlnaHRzID0gYygwLjIsIDAuOCkpKwogIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gIkEiKQoKZ2dzYXZlKHBsb3QgPSB0ZXN0X2NvciwgZmlsZW5hbWUgPSAiYXJlYS5wdXAxLmRuYS5nZnBfY29yLnBkZiIsIHBhdGggPSAifi9wbG90cy9wYXBlcjEvZmlndXJlcy9maWdfMi8iLCB3aWR0aCA9IDYuNSwgaGVpZ2h0ID0gNykKYGBgCgoKI1BhcnRpYWwgY29ycmVsYXRpb25zCnBwY29yCmBgYHtyfQojcGFydGlhbCBjb3JyZWxhdGlvbnMKcHBDb3IubGlzdCA8LSBtbHIuZGYyICU+JSAKICBmaWx0ZXIodHJlYXRtZW50ID09ICJub25lIikgJT4lIHNwbGl0KC4kZGVncm9uKSAlPiUgCiAgbWFwKC4sZnVuY3Rpb24oYSl7CiAgICBhIDwtIGEgJT4lIAogICAgICBkcGx5cjo6c2VsZWN0KHQuaGFsZiwgYXJlYSwgIGRhcGkuc3VtLmJnLnN1Yi5wdW5jdGEsIHJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEsIGdmcC5tZWFuLmJnLmFmLnN1Yi5uZXcpICU+JSAKICAgICAgbmEub21pdCgpCiAgICBwcGNvcjo6cGNvcihhKQogIH0pCgojY29ycmVsYXRpb25zCmNvci5hbGwgPC0gbWxyLmRmMiAlPiUgCiAgZmlsdGVyKHRyZWF0bWVudCA9PSAibm9uZSIpICU+JSAgCiAgc3BsaXQoLiRkZWdyb24pICU+JSAKICBtYXAoLixmdW5jdGlvbihhKXsKICAgICBhIDwtIGEgJT4lIAogICAgICBkcGx5cjo6c2VsZWN0KHQuaGFsZiwgYXJlYSwgZGFwaS5zdW0uYmcuc3ViLnB1bmN0YSxyZnAubWVhbi5iZy5zdWIucHVuY3RhLCBnZnAubWVhbi5iZy5hZi5zdWIubmV3KSAlPiUgCiAgICAgIG5hLm9taXQoKQogICAgIGNvcihhKQogIH0pCgpgYGAKCmBgYHtyfQpwcENvci5kZiA8LSBwcENvci5saXN0ICU+JSAKICBtYXAoLixmdW5jdGlvbihhKXsKICAgIGEkZXN0aW1hdGUgJT4lIAogICAgICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgICByb3duYW1lc190b19jb2x1bW4odmFyID0gInJlZ3Jlc3NvciIpICU+JSAKICAgICAgZHBseXI6OnNlbGVjdCh0LmhhbGYsIHJlZ3Jlc3NvcikgJT4lIAogICAgICBsZWZ0X2pvaW4oLixhJHAudmFsdWUlPiUgCiAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgICAgICAgICAgICAgICAgIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAicmVncmVzc29yIikgJT4lIAogICAgICAgICAgICAgICAgICByZW5hbWUoInAudmFsdWUiID0gInQuaGFsZiIpICU+JSAKICAgICAgZHBseXI6OnNlbGVjdChwLnZhbHVlLCByZWdyZXNzb3IpLCBieSA9ICJyZWdyZXNzb3IiKQogIH0pICU+JSAKICBiaW5kX3Jvd3MoLmlkID0gImRlZ3JvbiIpCgpzaW5nbGUuY29yZS5kZiA8LSBjb3IuYWxsICU+JSAKICBtYXAoLixmdW5jdGlvbihhKXsKICAgIGElPiUgCiAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgICAgIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAicmVncmVzc29yIikgJT4lIAogICAgICBkcGx5cjo6c2VsZWN0KHQuaGFsZiwgcmVncmVzc29yKQogIH0pICU+JSAKICBiaW5kX3Jvd3MoLmlkID0gImRlZ3JvbiIpICU+JSAKICByZW5hbWUoInNpbmdsZS5jb3JlIj0idC5oYWxmIikKCmBgYAoKYGBge3J9CmxpYnJhcnkoZ3Rvb2xzKQpgYGAKCmBgYHtyfQpwcENvb3IuZmlnIDwtIHBwQ29yLmRmICU+JSAKICBsZWZ0X2pvaW4oLixzaW5nbGUuY29yZS5kZiwgYnkgPSBjKCJkZWdyb24iLCJyZWdyZXNzb3IiKSkgJT4lIAogIHJlbmFtZSgiUGFydGlhbC1QYXJpd2lzZSI9InQuaGFsZiIsCiAgICAgICAgICJTdGFuZGFyZC1QYXJpd2lzZSIgPSAic2luZ2xlLmNvcmUiKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKCJQYXJ0aWFsLVBhcml3aXNlIiwiU3RhbmRhcmQtUGFyaXdpc2UiKSkgJT4lIAogICBtdXRhdGUocmVncmVzc29yID0gY2FzZV93aGVuKHJlZ3Jlc3NvciA9PSAiZ2ZwLm1lYW4uYmcuYWYuc3ViLm5ldyIgfiAiR0ZQIiAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdyZXNzb3IgPT0gImFyZWEiIH4gIkFyZWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVncmVzc29yID09ICJyZnAubWVhbi5iZy5zdWIucHVuY3RhIiB+ICJQdXAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ3Jlc3NvciA9PSAiZGFwaS5zdW0uYmcuc3ViLnB1bmN0YSIgfiAiRE5BIiAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdyZXNzb3IgPT0gInQuaGFsZiIgfiAiaGFsZi1saWZlIiksIAogICAgICAgICAgZGVncm9uID0gZmFjdG9yKGRlZ3JvbiwgbGV2ZWxzID0gYygieWVHRlAtbU9EQyIsInllR0ZQLUNMTjIiLCJ5ZUdGUCIpKSwgCiAgICAgICAgICBuYW1lID0gZmFjdG9yKG5hbWUgLCBsZXZlbHMgPSBjKCJTdGFuZGFyZC1QYXJpd2lzZSIsICJQYXJ0aWFsLVBhcml3aXNlIikpLCAKICAgICAgICAgIHNpZyA9IHN0YXJzLnB2YWwocC52YWx1ZSksIAogICAgICAgICAgc2lnID0gaWZlbHNlKHNpZyA9PSAiICIsICJOUyIsIHNpZykpICU+JSAKICAjIGZpbHRlcihwLnZhbHVlIDwgMC4wNSkgJT4lIAogIGZpbHRlcihyZWdyZXNzb3IgIT0gImhhbGYtbGlmZSIpICU+JSAKICBnZ3Bsb3QoLixhZXMoeCA9IHJlZ3Jlc3NvciAsIHkgPSB2YWx1ZSwgZmlsbCA9IG5hbWUpKSsKICBnZW9tX2NvbCh3aWR0aCA9IDAuNSwgcG9zaXRpb24gPSAiZG9kZ2UiKSsKICBmYWNldF93cmFwKH5kZWdyb24pKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIHNpemUgPSAwLjEpKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoLTAuNSwwLjUsIGJ5ID0gMC4xKSkrCiAgdGhlbWVfcHVicigpKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDQsIm1tIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShzaXplID0gMC4xKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJsaWdodHN0ZWVsYmx1ZTQiICwiIHN0ZWVsYmx1ZTQiKSwgbmFtZSA9IE5VTEwpKwogIHlsYWIoIkNvcnJlbGF0aW9uIHdpdGggSGFsZi1saWZlICIpKwogIHhsYWIoIkNlbGx1bGFyIGZlYXR1cmVzIikKCnBwQ29vci5maWcKYGBgCiNwYXRjaHdvcmsgZm9yIDQgY2VsbHVsYXIgZmVhdHVyZXMgKGFyZWEsIGdmcCwgZGFwaSwgcHVwMSkgYW5kIHQtaGFsZiAKCmBgYHtyIGZpZy53aWR0aD0gNSwgZmlnLmhlaWdodD0gNn0KZ2ZwLjRjb3IuaGYucHBDb3IucGx0IDwtIChnZnAuNi5jb3IucGx0L3Zhci5leHAucGx0L3BwQ29vci5maWcpKwogIHBsb3RfbGF5b3V0KCBoZWlnaHRzID0gYygwLjYsMC4yLCAwLjIpKSsKICBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9ICJBIikKCmdmcC40Y29yLmhmLnBwQ29yLnBsdApgYGAKCmBgYHtyfQpnZ3NhdmUocGxvdCA9IGdmcC40Y29yLmhmLnBwQ29yLnBsdCwgZmlsZW5hbWUgPSAiZ2ZwXzRjb3JfaGFsZkxpZmVfcHBjb3IucG5nIiwgcGF0aCA9ICJ+L3Bsb3RzL3BhcGVyMS9maWd1cmVzL2ZpZ18yLyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gOSkKCmdnc2F2ZShwbG90ID0gZ2ZwLjRjb3IuaGYucHBDb3IucGx0LCBmaWxlbmFtZSA9ICJnZnBfNGNvcl9oYWxmTGlmZV9wcGNvci5wZGYiLCBwYXRoID0gIn4vcGxvdHMvcGFwZXIxL2ZpZ3VyZXMvZmlnXzIvIiwgd2lkdGggPSA3LCBoZWlnaHQgPSA5KQpgYGAKCiN3aXRoIHByb3RlaW4gaW5oaWJpb24KYGBge3J9CnBwQ29yLlBydEluLmxpc3QgPC0gbWxyLmRmICU+JSAKICAgIGZpbHRlcih0cmVhdG1lbnQgIT0gIm5vbmUiKSAlPiUgIAogIGZpbHRlcihpZmVsc2UodHJlYXRtZW50ID09ICI1dU0iLCB0LmhhbGYgPCAxMzguNjI5NCwgdC5oYWxmID09IHQuaGFsZikpICU+JSAKICBzcGxpdCguJHRyZWF0bWVudCkgJT4lIAogIG1hcCguLGZ1bmN0aW9uKGEpewogICAgYSA8LSBhICU+JSAKICAgICAgZHBseXI6OnNlbGVjdCh0LmhhbGYsIGFyZWEsIGRhcGkuc3VtLmJnLnN1Yi5wdW5jdGEsIHJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEsIGdmcC5tZWFuLmJnLmFmLnN1Yi5uZXcpICU+JQogICAgICBuYS5vbWl0KCkKICAgIHBwY29yOjpwY29yKGEpCiAgfSkKCmNvci5QcnRJbi5hbGwgPC0gbWxyLmRmICU+JSAKICAgIGZpbHRlcih0cmVhdG1lbnQgIT0gIm5vbmUiKSAlPiUgIAogIGZpbHRlcihpZmVsc2UodHJlYXRtZW50ID09ICI1dU0iLCB0LmhhbGYgPCAxMzguNjI5NCwgdC5oYWxmID09IHQuaGFsZikpICU+JSAKICBzcGxpdCguJHRyZWF0bWVudCkgJT4lIAogIG1hcCguLGZ1bmN0aW9uKGEpewogICAgYSA8LSBhICU+JSAKICAgICAgZHBseXI6OnNlbGVjdCh0LmhhbGYsIGFyZWEsIGRhcGkuc3VtLmJnLnN1Yi5wdW5jdGEsIHJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEsIGdmcC5tZWFuLmJnLmFmLnN1Yi5uZXcpICU+JSAKICAgICAgbmEub21pdCgpCiAgICBjb3IoYSkKICB9KQoKYGBgCgpgYGB7cn0KcHBDb3IuUHJ0SW4uZGYgPC0gcHBDb3IuUHJ0SW4ubGlzdCAlPiUgCiAgbWFwKC4sZnVuY3Rpb24oYSl7CiAgICBhJGVzdGltYXRlICU+JSAKICAgICAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICAgICAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJyZWdyZXNzb3IiKSAlPiUgCiAgICAgIGRwbHlyOjpzZWxlY3QodC5oYWxmLCByZWdyZXNzb3IpICU+JSAKICAgICAgbGVmdF9qb2luKC4sYSRwLnZhbHVlJT4lIAogICAgICAgICAgICAgICAgICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4odmFyID0gInJlZ3Jlc3NvciIpICU+JSAKICAgICAgICAgICAgICAgICAgcmVuYW1lKCJwLnZhbHVlIiA9ICJ0LmhhbGYiKSAlPiUgCiAgICAgIGRwbHlyOjpzZWxlY3QocC52YWx1ZSwgcmVncmVzc29yKSwgYnkgPSAicmVncmVzc29yIikKICB9KSAlPiUgCiAgYmluZF9yb3dzKC5pZCA9ICJ0cmVhdG1lbnQiKQoKc2luZ2xlLmNvcmUuUHJ0bi5kZiA8LSBjb3IuUHJ0SW4uYWxsICU+JSAKICBtYXAoLixmdW5jdGlvbihhKXsKICAgIGElPiUgCiAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgICAgIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAicmVncmVzc29yIikgJT4lIAogICAgICBkcGx5cjo6c2VsZWN0KHQuaGFsZiwgcmVncmVzc29yKQogIH0pICU+JSAKICBiaW5kX3Jvd3MoLmlkID0gInRyZWF0bWVudCIpICU+JSAKICByZW5hbWUoInNpbmdsZS5jb3JlIj0idC5oYWxmIikKYGBgCmNvcnJlbGF0aW9uIG9mIHB1cDEgd2l0aCBtT0RDIHdpdGggdHJlYXRlZCB3aXRoIHByb3RlYXNvbWUgaW5oaWJpdG9ycwpgYGB7cn0KcHBjb3IuZmlnLmRmIDwtIHBwQ29yLlBydEluLmRmICU+JSAKICBsZWZ0X2pvaW4oLixzaW5nbGUuY29yZS5QcnRuLmRmLCBieSA9IGMoInRyZWF0bWVudCIsInJlZ3Jlc3NvciIpKSAlPiUgCiAgZmlsdGVyKCEodHJlYXRtZW50ICVpbiUgYygiZG1zbzEiLCI1MHVNIikpKSAlPiUgCiAgcmVuYW1lKCJQYXJ0aWFsLVBhcml3aXNlIj0idC5oYWxmIiwKICAgICAgICAgIlN0YW5kYXJkLVBhcml3aXNlIiA9ICJzaW5nbGUuY29yZSIpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IGMoIlBhcnRpYWwtUGFyaXdpc2UiLCJTdGFuZGFyZC1QYXJpd2lzZSIpKSAlPiUgCiAgIG11dGF0ZShyZWdyZXNzb3IgPSBjYXNlX3doZW4ocmVncmVzc29yID09ICJnZnAubWVhbi5iZy5hZi5zdWIubmV3IiB+ICJHRlAiICwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ3Jlc3NvciA9PSAiYXJlYSIgfiAiQXJlYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdyZXNzb3IgPT0gInJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEiIH4gIlB1cDEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVncmVzc29yID09ICJkYXBpLnN1bS5iZy5zdWIucHVuY3RhIiB+ICJETkEiICwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ3Jlc3NvciA9PSAidC5oYWxmIiB+ICJoYWxmLWxpZmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiByZWdyZXNzb3IpLCAKICAgICAgICAgIHRyZWF0bWVudCA9IGZhY3Rvcih0cmVhdG1lbnQsIGxldmVscyA9IGMoImRtc28xIiwiNTB1TSIsImRtc28yIiwiMXVNIiwiMi41dU0iLCI1dU0iKSksIAogICAgICAgICAgbmFtZSA9IGZhY3RvcihuYW1lICwgbGV2ZWxzID0gYygiU3RhbmRhcmQtUGFyaXdpc2UiLCAiUGFydGlhbC1QYXJpd2lzZSIpKSwgCiAgICAgICAgICBzaWcgPSBzdGFycy5wdmFsKHAudmFsdWUpLCAKICAgICAgICAgIHNpZyA9IGlmZWxzZShzaWcgPT0gIlwgIiwgIk4uUyIsIHNpZykpCiAgICAgICAgICAjIG5ldy52YWx1ZSA9IGlmZWxzZSgobmFtZSA9PSAiUGFydGlhbC1QYXJpd2lzZSIgJiBwLnZhbHVlID4gMC4wNSksIDAsIHZhbHVlKSkgJT4lIAogICMgZmlsdGVyKHAudmFsdWUgPCAwLjA1KSAlPiUgCnBwY29yLmZpZy5kZiAlPiUgCiAgZmlsdGVyKCEocmVncmVzc29yICVpbiUgYygiaGFsZi1saWZlIiwgInNoYXBlIikpLCAKICAgICAgICAgcmVncmVzc29yID09ICJQdXAxIiwgCiAgICAgICAgIHRyZWF0bWVudCAlaW4lIGMoImRtc28yIiwiMXVNIiwiMi41dU0iLCI1dU0iKSkgJT4lIAogIGdncGxvdCguLGFlcyh4ID0gdHJlYXRtZW50ICwgeSA9dmFsdWUsIGZpbGwgPSBuYW1lKSkrCiAgZ2VvbV9jb2wod2lkdGggPSAwLjUsIHBvc2l0aW9uID0gImRvZGdlIikrCiAgZ2VvbV90ZXh0KGRhdGEgPSBwcGNvci5maWcuZGYgJT4lIAogICAgICAgICAgICAgIGZpbHRlcighKHJlZ3Jlc3NvciAlaW4lIGMoImhhbGYtbGlmZSIsICJzaGFwZSIpKSwgCiAgICAgICAgIHJlZ3Jlc3NvciA9PSAiUHVwMSIsIAogICAgICAgICB0cmVhdG1lbnQgJWluJSBjKCJkbXNvMiIsIjF1TSIsIjIuNXVNIiwiNXVNIikpICwgCiAgICAgICAgIGFlcyhsYWJlbCA9IHNpZyksIG51ZGdlX3ggPSAtMC4xKSsKICAjIGZhY2V0X3dyYXAofnRyZWF0bWVudCwgbnJvdyA9IDEpKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoLTAuNSwwLjUsIGJ5ID0gMC4xKSkrCiAgdGhlbWVfcHVicigpKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDQsIm1tIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImxpZ2h0c3RlZWxibHVlNCIgLCIgc3RlZWxibHVlNCIpLCBuYW1lID0gTlVMTCkrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkrCiAgeWxhYigiQ29ycmVsYXRpb24gb2YgUHVwMSB3aXRoIEhhbGYtbGlmZSAiKSsKICB4bGFiKCJQcm90ZWluIGluaGliaXRvciB0cmVhdG1lbnQgKE1HMTMyKSIpCmBgYAoKI3doZW4geW91IG5vcm1hbGl6ZSBwdXAxIHdpdGggdGhlIGFyZWEKYGBge3J9Cm1sci5kZiAlPiUKICBtdXRhdGUoZG0gPSBsb2cxMChkbSkpICU+JSAKICBmaWx0ZXIoZGVncm9uICVpbiUgYygibU9EQy4yIiwgImNsbjIuMyIsICJjbG4yLjQiLCAic3RhYmxlLjIiLCAic3RhYmxlLjMiKSkgJT4lCiAgZHBseXI6OnNlbGVjdCh0LmhhbGYsCiAgICAgICAgIHJlZ3Jlc3NvcnMsCiAgICAgICAgIGRlZ3JvbikgJT4lCiAgcmVuYW1lKAogICAgIkdGUCIgPSAiZ2ZwLm1lYW4uYmcuYWYuc3ViLm5ldyIsCiAgICAiUHVwMS10RGltZXIiID0gInJmcC5tZWFuLmJnLnN1Yi5wdW5jdGEiLAogICAgIkROQSIgPSAiZGFwaS5zdW0uYmcuc3ViLnB1bmN0YSIsCiAgICAiQXJlYSIgPSAiYXJlYSIKICApICU+JQogIG11dGF0ZShub3JtLnB1cDEgPSBgUHVwMS10RGltZXJgL0FyZWEpICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IGMoMjo3LDkpKSAlPiUKICBtdXRhdGUoZGVncm9uID0gY2FzZV93aGVuKAogICAgICBkZWdyb24gJWluJSBjKCJjbG4yLjMiLCAiY2xuMi4yIiwgImNsbjIiLCAiY2xuMi40IikgfiAieWVHRlAtQ0xOMiIsCiAgICAgIGRlZ3JvbiAlaW4lIGMoIm1PREMuMiIsICJtT0RDIikgIH4gInllR0ZQLW1PREMiLAogICAgICBkZWdyb24gJWluJSBjKCJzdGFibGUiLCAic3RhYmxlLjIiLCAic3RhYmxlLjMiKSB+ICJ5ZUdGUCIKICAgICksCiAgICBkZWdyb24gPSBmYWN0b3IoZGVncm9uICwgbGV2ZWxzID0gYygieWVHRlAtbU9EQyIsICJ5ZUdGUC1DTE4yIiwgInllR0ZQIikpCiAgKSAlPiUKICBmaWx0ZXIoIShuYW1lICVpbiUgYygic2hhcGUiLCJkbSIpKSkgJT4lIAogIGdncGxvdCguLCBhZXMoeCA9IHZhbHVlLCB5ID0gdC5oYWxmKSkgKwogICAgICBnZ3BvaW50ZGVuc2l0eTo6Z2VvbV9wb2ludGRlbnNpdHkoc2l6ZSA9IDAuMiwgZ3VpZGVzID0gRikgKwogICAgICBzdGF0X2NvcihzaXplID0gMikgKwogICAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJyZWQ0Iiwgc2l6ZSA9IDAuNSkrCiAgICAgIGZhY2V0X3dyYXAoZGVncm9uIH4gbmFtZSwgc2NhbGVzID0gImZyZWUiLCBuY29sID0gNCkgKwogICAgICB0aGVtZV9idygpICsKICAgICAgbGFicyh4ID0gTlVMTCkgKwogICAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCksCiAgICAgICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMiwibW0iKSwgCiAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikrCiAgeWxhYigiSGFsZi1MaWZlIFttaW4uXSIpKwogIHhsYWIoIkEuVSIpCmBgYAoK